How to use `import/require` with dynamic path?

I would like to use import/require with dynamic path, for example

const path = '../imports/modules/core/startup/client';

import path;

This won’t be possible because imports need to be at the start of one file.

Solutions:

  1. you could use require(randomPath)
  2. Export the file and import it in this one, though I’m not quite sure if that will work

Thanks for your reply.
Could you example for require()?
(don’t understand 2…)

1 Like

I tries

let path = '../imports/modules/core/startup/client';
require(path);

But don’t work.

1 Like
var path = '../imports/modules/core/startup/client';

var variableName = require(path);

file-one.js

export const path = '../imports/modules/core/startup/client';

file-two.js

import { path } from './file-one.js'; 
import path;

I tried, but don’t work.
I use Meteor 1.3, I would like to import/require startup index file from imports folder.
For example:

// imports/startup/client/index.js
import './routes.js';

// client/main.js
var path = '../imports/startup/client';
var variableName = require(path);
1 Like

Yes, i get that.

Then simply do this:

import '/imports/startup/client';

Thanks again, but I must to use dynamic path
For example:

var module = ['A', 'B'];

module.forEach(function (val) {
   // require/import --> '/imports/startup/client/'+val;
});
2 Likes

Hmm ok so i tested for a little bit and i don’t find any solution to your problem

Now I found two npm packages: require-alias, load-alias.
And I tried to use it, but don’t work.

I think that what you want is simply not possible at all.

Babel transpiles your code at compile time. It parses all “import statements” it sees in your code.

When you write something like ["a", "b"].forEach(path => { import path; }); Babel only sees 1 import statement and thereby tries to parse that statement. Except, in that translation, path has no value as it doesn’t run the code, it only translates.

1 Like

I have the same problem, trying to use reflection to dynamically import things based on the URL.

this is such a basic feature to have, i’m trying to do this and surprisingly it doesn’t work //=

this kind of require always has been the magic sauce of my applications : (

really need a workaround for this…

as @chulian said, there are many reasons to want a dynamic require, specially on the backend!

1 Like

It does seem like a basic feature.

Imports in principal can’t be dynamic. The bundler has to know what to bundle into the client-bundle.
It works in some edge cases (when the file has already been bundled).

That is surely NOT a basic feature. ES2015 has no concept of dynamic imports.

There has also been some discussion on this topic here: https://forums.meteor.com/t/dynamic-imports-file-names

there is however one way to do something similar:

// impors/folder contains multiple modules
import * as StuffToImport from 'imports/folder';

// now you have StuffToImport.moduleA, StuffToImport.moduleB, etc.



Sorry to revive an old thread, but I saw this is one of the more frequently visited threads from google and doesn’t have a satisfactory answer. So I’ll just paste over these notes which should be on their way into the official docs at some point

Using import() with dynamic expressions

If you try to import using any computed expression, such as:

let path = 'example';
const module = await import(`/libs/${path}.js`);

You’ll get an error like so:

Error: Cannot find module '/libs/example.js'

Meteor’s build process builds a graph of all files that are imported or required
using static analysis. It then creates exact bundles of the referenced files
and makes them available to the client for import().

Without a complete import statement (static, dynamic or require), Meteor won’t
make that module available for import().

The solution to make dynamic expressions work is to create a module “whitelist”
that can be read by the build process, but does not actually run. For example:

if (false) {
  import("/libs/example.js");
  import("/libs/another-example.js");
  import("/libs/yet-another-example.js");
}

Make sure the whitelist is imported from both the client and server entry points.

Difference to other bundling systems

In Meteor’s implementation, the client has perfect information about which
modules were in the initial bundle, which modules are in the local cache, and
which modules still need to be fetched. There is never any overlap between
requests made by a single client, nor will there be any unneeded modules in the
response from the server. You might call this strategy exact code splitting,
to differentiate it from bundling.

Moreover, the initial bundle includes the hashes of all available dynamic
modules, so the client doesn’t have to ask the server if it can use a cached
version of a module, and the same version of the module never needs to be
downloaded again by the same client. This caching system has all the benefits of
immutable caching.

Meteor also allows dynamic expressions as long as the dependency is expressed
statically somewhere else in your code. This is possible because Meteor’s
client-side module system understands how to resolve dynamic strings at runtime
(which is not true in webpack or browserify, because they replace module
identifier strings with numbers). However, the set of available modules is
constrained by the string literals that you, the programmer, explicitly decided
to allow to be imported (either directly or in a whitelist).

5 Likes

Great! thanks for the explanation.
I found out that you can also use “sync” require

if (false) {
    require('/imports/i18n/home.cs.i18n');
}
const x = require(`/imports/i18n/home.${Meteor.settings.public.lang}.i18n`);
2 Likes