mjs转译为cjs(快来造轮子)

285 阅读1分钟

市场调研

2023.01.15 babel和webpack仍未解决.

babel: babel.docschina.org/repl/#?brow… 保留了top-level-await, 实属一脸蒙蔽

image.png

webpack: github.com/webpack/web… 额... rollup: github.com/rollup/roll… 貌似有人尝试了一波,然后又放弃了

mjs能不能转cjs

不用top-level-await能直接转, 跟esm转cjs一样, 用了就不能直接转, 必须用promise包一层.

top-level-await是啥:

res.mjs

const sleep = (time) => new Promise(resolve => {
  setTimeout(() => resolve(1), time);
});

(async () => {
  for (let i = 0; i < 1000 * 1000; i++) {
    await sleep(500);
    console.log('from res.mjs', i);
  }
})();

export const foo = 1;

const res = await sleep(2000); // mjs最外层能使用await,最外层的就是top-level-await

export default res;

index.mjs

console.log('run');

import res, { foo } from './res.mjs';

const sleep = (time) => new Promise(resolve => {
  setTimeout(() => resolve(1), time);
});

(async () => {
  for (let i = 0; i < 1000 * 1000; i++) {
    await sleep(500);
    console.log('from index.mjs', i);
  }
})();

console.log('res', res);

执行结果:

image.png

所以,用了top-level-await后,import res from './res.mjs'得等到res.mjs执行完之后, 再执行后面的代码。

如何转

res.mjs -> res.cjs

// 1. 封装promise
const mjsPromise_res = async () => {
    // 2. 创建module
    const module = {};

    const sleep = (time) => new Promise(resolve => {
      setTimeout(() => resolve(1), time);
    });

    (async () => {
      for (let i = 0; i < 1000 * 1000; i++) {
        await sleep(500);
        console.log('from res.mjs', i);
      }
    })();

    // 3. 导出语法转换
    module.foo = 1;

    const res = await sleep(2000); // mjs最外层能使用await,最外层的就是top-level-await

    // 3. 导出语法转换
    module.default = res;
    
    // 4. 导出
    return module;
};

export default mjsPromise_res;

index.mjs -> index.cjs

// 1. import转为promise,并提升到文件最顶部
const mjsPromise_res = require('./res.mjs');

// 2. 执行promise, 并将文件内的内容原封不动放入then中, then的参数也得变
mjsPromise_res().then(async ({ default: res, foo }) => {
    console.log('run');

    const sleep = (time) => new Promise(resolve => {
      setTimeout(() => resolve(1), time);
    });

    (async () => {
      for (let i = 0; i < 1000 * 1000; i++) {
        await sleep(500);
        console.log('from index.mjs', i);
      }
    })();

    console.log('res', res);
});

然后开始实现

等我(个屁, 又懒又菜),或者谁来帮忙...

mjs转cjs的意义何在

现在好多npm包都用mjs重写了, 如果作者正常写不用top-level-await的话还好, cjs写出来的包还是可以通过esm转cjs的方式去引用的, 就是得额外配置而已.

但是如果用了top-level-await, 那mjs和cjs就不能互相引用了, 因为至今好像都没人实现mjs转cjs的工具, 所以这个意义真的很大啊.