分类
js

Webpack 不支持 `import.meta`,利用 ESM 在浏览器里使用 yargs

前些天遇到一个需求:解析 curl 请求,并转换成 ajax 请求由浏览器发出去。

我觉得这个需求听起来不算稀罕,理论上应该有现成的库。于是在 npm 找了一下,发现 curlconverter 似乎可以满足需求。但是使用的时候报错:Module parse failed: Unexpected token

这个错误很奇怪,看起来像是 loader 没配好。打开报错的文件位置,怎么看语法都没问题。尝试修改 webpack 配置,也未果。因为项目是 vue-cli 创建的,在如何查看最终配置上也浪费很多时间。

最后继续诉诸 Google,关键词换来换去,终于在搜索 mjs Module parse failed: Unexpected token 时找到这个 issue:https://github.com/arnog/mathlive/issues/525,继而找到 https://github.com/webpack/webpack/issues/6719,终于确定,这是 webpack 的问题。

因为 webpack 不支持 import.meta,所以会把 import.meta 当成语法错报告。我觉得这个行为很扯,因为 loader 配错也会报这个,所以对于第一次接触到这个问题的开发者(比如我)而言,会浪费大量时间在那些初级错误的搜索结果里。

接下来解决问题。

curlconverter 虽然不能直接使用,但仔细阅读它的代码,其中 https://github.com/NickCarneiro/curlconverter/blob/master/util.js 解析 curl 命令的功能实现应该问题不大,我只要想办法把 yargs 加载进来即可。而 yargs 支持浏览器 ESM 加载,所以我在页面里添加了 <script type="module" src="./yargs.js">,使用如下代码:

// 虽然 yargs 已经到 16.2,但是 16.0.4 之后的版本都有问题
import Yargs from 'https://unpkg.com/yargs@16.0.3/browser.mjs';

// 加载完成 yargs 之后,把它挂载到 window 上
window.Yargs = Yargs;

将 yargs 挂到 window 上,成为外部库。然后在 vue.config.js 里配置 externals:

module.exports = {
  chainWebpack: config => {
    config.externals.yargs = 'commonjs Yargs';
  }
}

接下来,将前面说的 utils.js 复制到本地并修改其中 parseCurlCommand 的实现,最终完成了需求。


总结一下:

  1. 使用 yargs 解析命令行请求比较方便,远比自己写方便
  2. yargs 无法配合 webpack,据说可以配合 rollup 或者 snowpack,在我的 vue-cli 项目中,需要使用一些特殊的手段加载
  3. curlconverter 也很好用,可惜不能直接用
分类
前端工具链

解决“Error: Rule can only have one resource source (provided resource and test + include + exclude)”

又有一台服务器到期,不想续了,所以把东西往另一台服务器上搬。其中有一个小服务,用来存储 CI 测试失败的截图。里面有用到 font-awesome,但只用一个图标,太浪费。所以这次就顺手换成了 bootstrap-icons,然后顺便更新依赖,结果,再编译的时候,就报错:

ERROR  Error: Rule can only have one resource source (provided resource and test + include + exclude) in {
   "exclude": [
     null
   ],
   "use": [
     {
       "loader": "/Users/meathill/Projects/mini-store-admin/node_modules/@vue/cli-plugin-babel/node_modules/cache-loader/dist/cjs.js",
       "options": {
         "cacheDirectory": "/Users/meathill/Projects/mini-store-admin/node_modules/.cache/babel-loader",
         "cacheIdentifier": "219fb45a"
       },
       "ident": "clonedRuleSet-38[0].rules[0].use[0]"
     },
     {
       "loader": "/Users/meathill/Projects/mini-store-admin/node_modules/babel-loader/lib/index.js",
       "options": "undefined",
       "ident": "undefined"
     }
   ]
 }

非常诡异,按照错误栈点进去,从代码可以推断是生成的 webpack config 有问题,在 babel-loader 配置里既包含 resource 又包含 exclude。但是,这个项目是通过 @vue/cli 创建的,所以它的配置也是 @vue/cli-service 自动生成的,我并没有修改过。而且只有这个项目有问题,其它项目,同样使用 @vue/cli 创建,但是没有更新依赖,就没问题。

Google 之,有一些关于这个错误的讨论,但几乎都是用户自己写 webpack.config.js 没写好出问题。有人建议 rm -rf node_modules & rm package-lock.json & npm i,即重装所有依赖,我试了两次,也不行。

开始尝试、推翻、再尝试、再推翻。后来怀疑到 webpack ,在 package-lock.json 里查找之,发现安装的版本竟然是 5.1.0,而没有更新过依赖,可以正常编译的项目里都是 4.x。那基本可以确认了。

  1. 先删掉 node_modulespackage-lock.json
  2. 手动在 package.jsondevDependencies 里添加 "webpack": "^4.44.2"
  3. 重新安装全部依赖: npm i
  4. 尝试编译,npm run build,发现问题解决

总结

我猜问题是这样的:某些新版本的库要求 webpack@5,更新依赖时,根据依赖选择的规则,就以 webpack@5 作为主依赖安装。然而 @vue/cli 依赖 webpack@4,它自带的 webpack 配置无法兼容 webpack@5 ,于是就报错,不能继续编译。如果你也在使用 @vue/cli,那么请不要贸然升级 webpack@5。

分类
js 技术

基于 @vue/cli 的项目配置 browserslist

前些日子虽然写了 最近折腾 @babel/preset-env 的一些小心得,但其实没有正确的理解和配置 browserslist,所以今天问题又来了。