【问题标题】:Simple webpack build fails because of new ES syntax由于新的 ES 语法,简单的 webpack 构建失败
【发布时间】:2020-12-24 19:35:16
【问题描述】:

我有以下文件:

src/index.js

let foo = null ?? "waffles"

以及以下 webpack 配置:

import path from 'path'

const defaultConf = {
    name: 'default',
    entry: './src/index.js',
    output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist')
    }
}

export default defaultConf

构建失败:

ERROR in ./src/index.js 2:18
Module parse failed: Unexpected token (2:18)

环境是:

node v14.8.0
webpack@4.44.1

为什么我的构建失败了?
如何调试导致它失败的原因?
我该如何解决?

编辑:所述语法是supported by node(+所有主要浏览器)。期望构建会成功。

编辑:根据安东尼的回答,我可以让问题更具体:

  1. 显然,根据答案,wepback 正在尝试转换该代码。 为什么 webpack 会尝试转译该代码? 它是否在某些我不知道的默认值上运行?什么是默认值?
  2. 如果我被一些默认设置绊倒了,我怎样才能知道它是什么? Webpack docs 说如下:

开箱即用,webpack 不需要您使用配置文件。但是,它将假定您的项目的入口点是 src/index.js,并将在 dist/main.js 中输出结果,并针对生产进行了缩小和优化。

它还做了哪些其他假设?“优化”是什么意思?它如何缩小代码?如何检查默认配置?可能调试构建过程(即逐步调试)?

  1. 如何防止 webpack 尝试转译此代码? 如何设置语言级别?例如。到 es2020,其中无效合并是其中的一部分。

注意:这个问题的重点不是最终得到一段工作代码。如果我想要,我会做 foo = null ? null : "waffles" 而不是空合并。重点是揭开 webpack 的神秘面纱。

【问题讨论】:

  • webpack 说它可以选择es6 的模块语法样式,但它没有说esnext 这意味着它不支持es2020 语法:)
  • 我已经更新了我的答案。除非有严格的要求,否则我认为在 webpack 中使用 es5 语法并指示 webpack 使用 babel-loader 转译您的代码是可行的方法。还要确保你的 webpack 配置正在被使用。
  • 经过一些研究,我有了一个有根据的猜测。它仍然是猜想。默认情况下,Webpack 可能不会转译代码,但它会转换代码,因此需要了解它及其语法。 v4 不理解新的 ES 功能,但是 v5 开箱即用。为什么它需要理解它的一个例子是 prod 的代码优化。它将这个:let foo = null ?? "waffles"; console.log(foo) 转换为 console.log("waffles") - 它需要了解运算符的功能才能将其缩减为更短的版本。优化器在这方面实际上相当聪明。

标签: webpack webpack-4


【解决方案1】:

------------编辑:2020 年 9 月 18 日。

TL;DR。通常,webpack 配置文件是为 Node 编写的,因此它使用 CommonJS “语法” - 推荐。如果您希望将 webpack 配置编写为 es6 模块,则需要额外的步骤 - 使用 Babel 转译配置文件,或者使用标志 --experimental-modules 启动 Node。如果您的代码也编写为 es6+ 模块,则需要配置 webpack 以使用 babel 转译您的代码(而不是配置文件)。

Node.js 默认使用 Common.js。为了运行 es6 模块(还有其他模块类型 - AMD、Require.js 等),您需要转换这些模块,以便您的 Node 版本可以在您执行 node myscript.jsnpm run xyz 时运行这些模块。所以首先 Node 需要了解你的 webpack 配置。

在您的版本中 - v14.x - 节点实验模块默认启用,因此您可以运行 es6 配置/脚本,但您必须使用 .mjs 扩展名保存脚本文件或在包中添加 { "type": "module" } .json。见herehere

对于较旧的节点版本,您需要使用标志--experimental-modules 运行节点(默认情况下未启用)

要使用 es6 模块的配置运行 webpack,您可以将 es6 中的配置转换为 CommonJS,或者编写一个从 Javascript(在 es6 中)调用 webpack 的脚本。你可以这样做:

//in webpack.config.mjs
import path from 'path'

const defaultConf = {
    name: 'default',
    entry: './src/index.js',
    output: {
        filename: 'main.js',
        path: path.resolve() + '/dist'
    },
    module: {
      rules: [
        {
          use: 'babel-loader', //if your code is in es6+ you still need this transpiled
          test: /\.js$/,
          exclude: /node_modules/
        }
      ]
    }
}

export default defaultConf

然后使用上面的配置文件编写一个调用webpack的脚本,如下所示:

//webpack-runner.mjs
import webpack from 'webpack';
import defaultConf from './webpack.config.mjs';

const webpackRunner = webpack(defaultConf);

webpackRunner.run();

然后在 package.json "build": "node --experimental-modules webpack-runner.mjs 的脚本部分。请注意,在 Node v14 中启用了 node --experimental-modules。进一步reading.

编辑结束


无论如何,你的 webpack 配置应该是 CommonJS 格式 js var x = require('some-module) 或者你需要 babel 将 es6 代码转换成 CommonJs 模块。如果你不这样做,你的 webpack 配置将不会被转译,当你尝试构建时节点会抱怨。

如果你在你的 webpack 配置中这样做了——也许是在 webpack.config.babel.js 中,这可能只是 webpack 没有使用你的配置文件并且使用了标准默认值,这也不会转换你的代码。

在任一情况下,您都会收到此错误“Unexpected token...”。

下面的 webpack 配置为我和 webpack 工作,使用 babel-loader,转译了代码,我能够运行你的 index.js。

const path = require('path');

module.exports = [{
    name: 'default',
    entry: './src/index.js',
    output: {
        filename: 'main.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: { //added module section so that webpack uses babel-loader
          rules: [
            {
              use: 'babel-loader',
              test: /\.js$/,
              exclude: /node_modules/
            }
          ]
        }

},] //add other named configurations before closing the array.

如果出于某种原因你肯定想要使用 es6 语法的 webpack 配置,那么这是可能的,但你需要先转译它(webpack 配置) - 看看 thisthis

【讨论】:

  • 如何防止 webpack 尝试转译我的代码?我只想按原样包含它。我实际上想使用我们获得的所有新浏览器功能。忽略 ES6 语法中的配置。
  • 这取决于你需要 webpack 做什么。如果您只使用最高 es6 的 Javascript 功能并且您正在构建的浏览器采用了 es6,并且您没有进行任何其他类型的捆绑/转换,那么您甚至可能不需要 webpack。
  • 一般来说,webpack 的其他用途是 - 打包、资产管理和其他转换。我尝试调试 webpack 构建,但实际上是不可能的。我希望 webpack 对其底层所做的事情不要那么不透明。
  • 好的。您必须配置 webpack 以便它使用 es6 语法。
  • 告诉我怎么做。
【解决方案2】:

升级到Webpack 5 以启用?? 语法,而不会出现繁琐的转译问题。

我遇到的附带问题:

  1. Webpack 5 包含 terser 插件,因此无需将其包含在您的 devDependencies 中。 Terser 的 sourceMap 选项已被删除,因此如果您使用它,请将其从 terser 选项中删除。
  2. 我将 webpack-node-externals 插件升级到最新版本(我的升级到 3.0.0)。其whitelist 选项已重命名为allowlist

【讨论】:

    猜你喜欢
    • 2022-11-02
    • 2021-06-27
    • 2021-12-08
    • 1970-01-01
    • 2019-10-15
    • 2020-11-27
    • 2021-07-02
    • 1970-01-01
    • 2018-06-19
    相关资源
    最近更新 更多