gunhawk

gunhawk

Frontend Developer

Coding is part of my life, 加藤恵は大好き=。=

Webpack4支持打包第三方库quickjs-emscripten

作者: gunhawk时间: 2024-06-08javascript

解释ESM模块出错

编译quickjs-emscripten时, 会出现以下错误:

error  in ./node_modules/quickjs-emscripten-core/dist/index.mjs

Module parse failed: Unexpected token (1:731)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
> import{a as O,b as A,c as Q}from"./chunk-QM66IUK3.mjs";.......

这个错误说明webpack无法正确解析模块的语法, 一般vue-cli的生成的工程都有配置.mjs的解析, 可通过导出配置文件查看:

npx vue-cli-service inspect > webpack-config.js

通过搜索大致可以发现.mjs的相关配置

/* config.module.rule('mjs') */
{
  test: /\.mjs$/,
  type: 'javascript/auto',
  include: [
    /node_modules/
  ]
},

明明配置了但是还是解释不了, 怎么办? 所幸的是, 可以通过babel来转换一下. 生成的工程里其实也已经包含了babel, 所以可以直接拿来用. 以下配置参考如下:

// vue.config.js

module.exports = {
  ...
  chainWebpack: config => {
    config.module
      .rule('quickjs')
        .before('mjs')  // 加在mjs的规则之前
        .test(/quickjs.+\.mjs$/)
        .use('cache')
          .loader('cache-loader')
          .end()
        .use('babel')
          .loader('babel-loader')
          .options({
            presets: [
              ['@babel/preset-env', { targets: "defaults" }]
            ]
          })
          .end()    
  }
}

再次编译后, webpack就能正确解释quickjs-emscripten里的模块了. But.....

找不到模块?

解释错误是没有了, 但是仍然提示有错误:

ERROR  Failed to compile with 1 error                                                                      

This dependency was not found:

* @jitl/quickjs-wasmfile-release-sync/emscripten-module in ./node_modules/@jitl/quickjs-wasmfile-release-sync/dist/index.mjs

难道是没安装相应的模块? 但是通过查找node_modules, 是有@jitl/quickjs-wasmfile-release-sync这个文件夹的. What the hell? 这个原因着实搞不懂...

于是我新生一计, 通过alias指定不就好了:P

configureWebpack: {
  resolve: {
    alias: {
      '@jitl/quickjs-wasmfile-release-sync/emscripten-module': path.resolve(__dirname, 'node_modules/@jitl/quickjs-wasmfile-release-sync/dist/emscripten-module.browser.mjs')
    }
  },
}

这个问题也解决了, But......

不支持import.meta.url

由于quickjs-emscripten使用了ESM新特性import.meta.url. Webpack4是不支持且直接抛出以下异常:

error  in ./node_modules/@jitl/quickjs-wasmfile-release-sync/dist/emscripten-module.browser.mjs

Module parse failed: Unexpected token (18:25)
File was processed with these loaders:
 * ./node_modules/cache-loader/dist/cjs.js
 * ./node_modules/babel-loader/lib/index.js
You may need an additional loader to handle the result of these loaders.
| import "core-js/modules/web.url-search-params.size.js";
| var QuickJSRaw = (() => {
>   var _scriptDir = import.meta.url;

OMG! 难道只能换webpack5或者vite? 这可是伤筋动骨啊... 难道没有其他办法了?

THANKFULLY, 我们不是已经用alias指向某个.mjs文件了吗? 改成我们本地的某个文件不就好了? 只要不使用import.meta.url, 一切都好说!

最后按照这个思路改造了一下, 终于是能正确运行了...

还要再说几句

这个又是折腾的一天... 明明都一把年纪了, 而且都2024年了, 还要去折腾这些蛋疼的工程配置, 真的烦. 不过谁让我们的工程这么老旧呢, webpack4就算了, package-lock.json还是version1的(node14安装的版本), 以后还有得折腾, 要是有个给力点的人帮我做这种事情就好了...

另外工程里的jest还不能运行依赖quickjs-emscripten的单元测试, 理由是不支持dynamic import. 然后我看其本身也是用vitest进行单元测试的, 好吧也只能用vitest了. 而vitest从1.0后就要用node18+才能跑, 我们的项目还是node14, 只能望着涩涩发抖.

不过我现在已经成功集成并且跑了不少关于插件的测试用例啦, 在这里也小小祈祷一下公司有朝一日能用上吧:)