使用包

有时包没有按照你期望的方式打包,你必须调整 Webpack 解释它们的方式。Webpack 提供了多种方法来实现这一目标。

resolve.alias

有时包不符合标准规则,而包中的 package.json 包含错误 main 字段。此时,我们完全可以丢弃它,使用 resolve.alias 字段,如下例所示:

{
  resolve: {
    alias: {
      demo: path.resolve(
        __dirname,
        "node_modules/demo/dist/demo.js"
      ),
    },
  },
},

如果 Webpack 解析器在开始时匹配到了 demo,它将对匹配目标进行解析。您可以使用类似 demo$ 的模式来精确约束匹配的过程。

轻量级的 React 替代品,例如 Preactreact-liteInferno,拥有更小的尺寸,但可能会舍弃诸如propTypes、事件处理之类的功能。用更轻的替代品替换 React 可以节省大量空间,但在这之前你应该做一些测试。

如果您使用 react-lite,请按如下所示进行配置:

{
  resolve: {
    alias: {
      // 按照你的需要进行替换
      react: "react-lite",
      "react-dom": "react-lite",
    },
  },
},

同样的技术也适用于 loader。类似地,你可以使用 resolveLoader.alias。您可以通过该方法在 Webpack 中运行 RequireJS 项目。

resolve.extensions

默认情况下,导入时如果没有包含扩展名,WebPack 只能解析以 .js.json 结尾的文件,如果要处理 JSX 文件,可以按以下方式进行调整:

{
  resolve: {
    extensions: [".js", ".json", ".jsx"],
  },
},

resolve.modules

可以通过更改 Webpack 查找模块的位置来改变模块解析过程。默认情况下,它仅在_node_modules_ 目录中查找。如果你想覆盖那里的包,你可以告诉 Webpack 首先查看其他目录:

{
  resolve: {
    modules: ["my_modules", "node_modules"],
  },
},

更改后,Webpack 将首先尝试查看 my_modules 目录。该方法适用于要自定义包解析的大型项目。

resolve.plugins

Webpack 允许您使用 `resolve.plugins 字段自定义模块解析行为。请考虑以下插件示例:

  • directory-named-webpack-plugin 将针对目录的导入映射到与目录名匹配的文件。例如,它将 import foo from "./foo"; 映射到 import foo from "./foo/foo.js"; 上。该模式在 React 中很受欢迎,使用该插件可以简化代码。通过 babel-plugin-module-resolver, Babel 可以实现相同的行为。
  • webpack-resolve-short-path-plugin 旨在避免深度嵌套导入,例如 import foo from "../../../foo"; 。通过添加对波浪号(~)语法的支持,import foo from "~foo" 将会直接从根目录解析 foo 文件。

在 Webpack 之外使用包

浏览器依赖(如jQuery)通常通过内容分发网络(CDN)提供。CDN 帮助您解决在各个地域加载流行软件包的问题。如果已经从 CDN 加载了包并且它在用户缓存中,那么在 Webpack 中就无需加载它。

要使用此技术,您应首先将所涉及的依赖项标记为外部:

externals: {
  jquery: "jquery",
},

现在,您需要将包的加载指向 CDN 并且理想情况下提供本地回退,一旦 CDN 无法工作,我们也可以从本地加载:

<script src="//ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
    window.jQuery || document.write('<script src="js/jquery-3.1.1.min.js"><\/script>')
</script>

如果您正在使用 HtmlWebpackPlugin 并希望自动注入 script 标记,则 html-webpack-cdn-plugin 是一个不错的选择。

处理全局变量

有时模块依赖于全局变量。由 jQuery 提供 $ 是一个很好的例子。Webpack 提供了一些允许您处理它们的方法。

注入全局变量

imports-loader 允许您注入全局变量,如下所示:

{
  module: {
    rules: [
      {
        // 解析包的地址
        // require.resolve 可以返回包的地址
        test: require.resolve("jquery-plugin"),
        loader: "imports-loader?$=jquery",
      },
    ],
  },
},

解析全局变量

Webpack ProvidePlugin 允许 Webpack 在遇到全局变量时解析它们:

{
  plugins: [
    new webpack.ProvidePlugin({
      $: "jquery",
    }),
  ],
},

将全局变量暴露给浏览器

有时您必须将包公开给第三方脚本,expose-loader 可以达到这个目的:

{
  test: require.resolve("react"),
  use: "expose-loader?React",
},

通过小的额外调整,该技术可通过 React.Perf 全局变量将 React 性能实用程序暴露给浏览器。您必须将以下代码插入应用程序入口点才能使其正常工作:

if (process.env.NODE_ENV !== "production") {
  React.Perf = require("react-addons-perf");
}

React Developer Tools 安装到 Chrome 中以获取更多信息是一个好主意,因为它允许您检查应用程序的 propsstate

script-loader 允许您在全局上下文中执行脚本。如果您使用的脚本依赖于全局上下文,则必须执行此操作。

删除未使用的模块

尽管软件包可以开箱即用,但它们有时会为您的项目带来太多代码。Moment.js 是一个流行的例子。默认情况下,它会将区域设置数据带到项目中。

禁用该行为的最简单方法是使用 IgnorePlugin 忽略语言环境:

{
  plugins: [new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/)],
},

您可以使用相同的机制来解决有问题的依赖项。例如:new webpack.IgnorePlugin(/^(buffertools)$/)

要将特定语言环境引入到项目中,您应该使用 ContextReplacementPlugin

{
  plugins: [
    new webpack.ContextReplacementPlugin(
      /moment[\/\\]locale$/,
      /de|fi/
    ),
  ],
},

上面的方法有一个栈溢出问题,其中有更多的技术细节。另见 Ivan Akulov 对 ContextReplacementPlugin 的解释

管理预构建的依赖项

对于特定依赖,Webpack 可能会给出以下警告:

WARNING in ../~/jasmine-promises/dist/jasmine-promises.js
Critical dependencies:
1:113-120 This seems to be a pre-built javascript file. Though this is possible, it's not recommended. Try to require the original source to get better results.
 @ ../~/jasmine-promises/dist/jasmine-promises.js 1:113-120

如果包指向预先构建(即已缩小且已处理)的文件,则可能发生警告。Webpack 检测到这种情况并发出警告。

如上所述,可以通过将包别名化为源版本来消除警告。鉴于有时候源不可用,另一个选择是通过 module.noParse 告诉 Webpack 跳过解析该文件。它接受 RegExp 或 RegExps 数组,可以如下配置:

{
  module: {
    noParse: /node_modules\/demo-package\/dist\/demo-package.js/,
  },
},

禁用警告时要小心,因为它可能隐藏潜在的问题。最好考虑替代方案。有一个 webpack issue,详细讨论了这个问题。

管理软链接

符号链接或软链接是一种操作系统级功能,允许您通过文件系统指向其他文件而无需复制它们。您可以使用 npm link 为正在开发的包创建全局软链接,也可以使用 npm unlink 来删除链接。

Webpack 会像 Node 一样将软链接解析为完整路径。问题是如果你不知道这个事实,这种行为会让你大吃一惊,特别是如果你依赖 Webpack 的软链接处理行为。webpack issue #1643#985中讨论的方法可以解决这个问题。Webpack 核心行为将来可能会有所改进,使这些变通方法变得不必要。

您可以通过设置 resolve.symlinksfalse 禁用 Webpack 的软链接处理。

深入了解包

为了获得更多信息,npm 提供了基本查询的命令 npm info <package>。您可以使用它来检查与包关联的元数据,同时确定版本相关信息。请考虑以下工具:

  • package-config-checker 更进一步。它允许您更好地了解项目的哪些软件包最近有更新,并提供了深入了解依赖项的途径。例如,它可以揭示哪些包的下载尺寸可以有所改进。
  • slow-deps 可以揭示项目的哪些依赖项安装的最慢。
  • 当以不同方式(未压缩,缩小,压缩)的向浏览器提供包时,weigh 可以用来计算包的大致大小。

总结

Webpack 可以正常地使用大多数 npm 软件包。但有时候,需要对 Webpack 的解析机制进行调整。

回顾一下:

  • 使用 Webpack 的模块解析给您带来很多好处。有时您可以通过调整解析机制来解决问题。不过,尝试改进上游项目本身会更好。
  • Webpack 允许您对已解析的模块进行调整。有些时候希望通过全局变量的方式来解决特定依赖,你可以直接注入它们。您还可以将模块公开为全局变量,因为这对于某些开发工具来说是必需的。
用户头像
登录后发表评论