javascriptnode.jsnode-modules

How do I set a node module import path as a variable?


I have 2 seperate files with various JS functions on them. I want to import either one based on a condition. I am unsure how to do this.

I have:

import { mainURL } from '../../support/helperFunctions.js';

let dataPath = '../../../data/data.js';
if (mainURL.includes('dev')) {
    dataPath = '../../../data/dataDev.js';
}
import { coreData, lastUpdated } from dataPath;

But I get the error Unexpected token for the import line.

I've also tried

if (mainURL.includes('dev')) {
    import { coreData, lastUpdated } from '../../../data/dataDev.js';
}
else {
    import { coreData, lastUpdated } from '../../../data/data.js';
}

And a few other variations of this.

Would anyone know how to achieve this in node?


Solution

  • You can import the data module via dynamic import or both modules then decide which one to use.

    Dynamic Import

    import { mainURL } from './helperFunctions.js';
    
    const pathToImport = mainURL.includes('dev')
      ? './data/dataDev.js'
      : './data/data.js'
    ;
    
    // import dynamically
    const { coreData, lastUpdated } = await import(pathToImport);
    
    console.log('lastUpdated', lastUpdated);
    console.log('coreData', coreData);
    

    Remember, using import(pathToImport) returns a promise and should be awaited (top-level await).

    The whole idea revolves around finding the target module path to load. I prefer this method because it is clear and straightforward.

    However, in some situations, dynamic loading requires extra effort. Bundlers for example, by default, do not include un-imported and unused files in the target package. Since your data files do not appear in any static import statement, they will be considered unused by bundlers and you should include and tune them somewhere in their configurations. To address those situations, you can easily import both and then decide which one to use:

    Static Import

    import { mainURL } from './helperFunctions.js';
    import * as dataDev from './data/dataDev.js';
    import * as data from './data/data.js';
    
    const { coreData, lastUpdated } = mainURL.includes('dev')
      ? dataDev
      : data
    ;
    
    console.log('lastUpdated', lastUpdated);
    console.log('coreData', coreData);
    

    In either case, the target bundle filesize remains the same, and both modules must be available at runtime. It really just comes down to your personal preference.