When dynamic import Computed module specifiers meteor?

I am seriously sad about this trying to use dynamic imports but can’t use dynamic files/variables with it which makes these imports not dynamic.

The files that need to be dynamiclly imported are not known until the runtime in my case until the route is loaded with a slug which load a diferent form but because dynamic imports currentyly doesn’"t accept variable but just strings it doesn’t work at all.

The only choice I have loaded all the form (lots of them) on the same route then just call one of them.

So according to this and following their suggestion:

//Computed module specifiers  #
//For applications such as internationalization, it helps if you can dynamically compute module specifiers:

import(`messages_${getLocale()}.js`)// 
.then(···);

This doesn’t work in meteor WHY??
What solution and what workaround???

lots of people talking about this…


1 Like

its dynamic in a sense, that you can request a module on runtime.

But meteor has to know on build-time, which modules can be requested by client. Imagine that the client would do:

const path = "/server/mysuperprivatesecret.js" 
import(path);

this would be very dangerous. That’s why the server has to know which modules should be made available to the client.

meteor does this by looking at all import("<somestring>") and register all these modules as loadable by the client. It does this statically, so that you can’t do import(`messages_${getLocale()`}.js, because the server could not know, what getLocale() can be.

Edit as you probably know all possible locales, you can do:


const LOCALES = {
  en: import("messages_en.js"),
  fr: import("messages_fr.js"),
  de: import("messages_de.js"),
  ....
}

const loadMessages = locale => LOCALES[locale].then( ...)


EDIT2: sorry, the above code does load all locales, this is better:


const LOCALES = {
  en: () => import("messages_en.js"),
  fr: () => import("messages_fr.js"),
  de: () => import("messages_de.js"),
  ....
}

const loadMessages = locale => LOCALES[locale]().then( ...)


2 Likes

The simplest solution I’ve found is to create a whitelist.

In a project I’m working on, we store which templates to load in the database and dynamically construct the import paths.

To make this work I have a file called dynamic-imports-whitelist.js that looks like this:

/**
 * This file exists to provide static references to Meteor's dynamic imports
 * implementation so they can be requested dynamically on the client
 * see: https://github.com/meteor/meteor/pull/8327#issuecomment-280876264
 */
// eslint-disable-next no-constant-condition
if (false) {
    import('meteor/dg:base');
    import('meteor/dg:base/client/modules/m_scrollingGrid');
    // ... etc
}

As long as the build tool sees the file name somewhere, it will make that file available for import. Sticking it in a dead code path (if (false)), means it doesn’t actually load on startup.


It would be very useful if someone had the time to add something like this to the Meteor Guide

1 Like

be careful with dead-code elimination :wink:

2 Likes

DOES NOT WORK is this I am becoming a witch trying to make spell or what the heck?

I am gonna import all with NOT SO dynamic import thing

1 Like

I get what you meant but that doesn’t solve my problem with dynamic variables in the import :frowning:

Did you make sure to import the whitelist so the build tool could see the import paths?

1 Like

yes I did even import all of that without even having the else and didn’t work on the client (although I imported that on the server not client)

ended up doing a massive switch case with all the form imports by hand :’(

Can you be a bit more specific about what you tried so we can help you?

I’ve been using this for most of the year with no issues. I construct the import paths like so:

    const page = Pages.findOne({ name: currentPage }, { reactive: false });
    Promise.all(
        page.layouts.map( ({ destData, templatePath }) => {
            // convert data and import templates
            const dataPromise = new Promise( (resolve, reject) => {
                // <snipped> load data for the template. Can be meteor method, ajax request, subscription, etc. 
            });
            // here's that dynamic path, straight from the database:
            const importPromise = import(templatePath);
            return Promise.all([dataPromise, importPromise]);
        })
    ).then( layouts => { // the result is a 2D array of data and templates
        Logger.debug('Successfully imported all templates for ' + page.name);
        // then render the templates using the imported data
    })

So for a simple page, this will be one dynamic import, and complex pages can have dozens of imports

Maybe there’s a difference with relative vs absolute paths?

1 Like

Just re-read your post.
The white-list needs to be imported to the platform that needs access to the paths. So you will need to import it on the client for the client to be able to dynamically import those paths

2 Likes