Skip to content

Instantly share code, notes, and snippets.

@WebReflection
Last active November 14, 2024 22:54
Show Gist options
  • Save WebReflection/6a9df9477b843956f589210f8ab371c0 to your computer and use it in GitHub Desktop.
Save WebReflection/6a9df9477b843956f589210f8ab371c0 to your computer and use it in GitHub Desktop.
PoC: How to inline ES modules
const env = {
m1: `import {func} from './m2.mjs'; console.log(func());`,
m2: `export function func() { return 'abc'; }`
};
const inlineModule = (env, text) => `data:text/javascript;base64,${
btoa(inlineModules(env, text))
}`;
const inlineModules = (env, text) => text.replace(
/('|")\.\/(.+?)\.m?js\1/g,
($0, delim, key) => `${delim}data:text/javascript;base64,${
btoa(inlineModules(env, env[key]))
}${delim}`
);
import(inlineModule(env, env.m1));
// read "abc" in console
@WebReflection
Copy link
Author

WebReflection commented Sep 11, 2019

Note for the reader: please, let's stop using .mjs already for every use case where it's not needed, like this one, thanks.


Limitations

  • if 2 modules import same 3rd module, this will be imported as fresh new module per each import
  • if the code contains the string "./some.js" anywhere, it easily breaks due poor RegExp implementation

Bear in mind, this is just a proof of concept.


Alternatives

@WebReflection
Copy link
Author

WebReflection commented Sep 11, 2019

Best option

with path resolution and URL objects too

const env = {
  m1: `
    import log from './utils/log.js';
    import {func} from './m2.js';
    log(func());
  `,
  m2: `export function func() { return 'abc'; }`,
  ['utils/log']: `export default console.log;`
};

const modules = new Map;

const resolve = (module, path) => {
  if (/^\/\//.test(path))
    return resolve('', path.slice(2));
  const real = module.split('/');
  const fake = path.split('/').filter(p => !/^(?:|\.)$/.test(p));
  real.pop();
  if (fake[0] === '.')
    fake.shift();
  while (fake[0] === '..') {
    real.pop();
    fake.shift();
  }
  return real.concat(fake).join('/');
};

const load = (env, module) =>
  modules.get(module) ||
  modules.set(
    module,
    URL.createObjectURL(
      new Blob(
        [env[module].replace(
          /('|")[./]+(.+?)\.m?js\1/g,
          ($0, delim, path) =>
            `${delim}${load(env, resolve(module, path))}${delim}`
        )],
        {type: 'text/javascript'
      })
    )
  ).get(module);

import(load(env, 'm1'));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment