模块方法

本节涵盖了使用 webpack 编译的代码中所有可用的方法。当使用 webpack 打包您的应用程序时,您可以从多种模块语法风格中选择,包括 ES6CommonJSAMD

虽然 webpack 支持多种模块语法,但我们建议遵循单一语法以保持一致性并避免奇怪的行为/错误。实际上,webpack 会针对 .mjs 文件、.cjs 文件或 .js 文件强制执行此建议,前提是它们最近的父级 package.json 文件包含一个 "type" 字段,其值为 "module""commonjs"。在继续阅读之前,请注意这些强制执行。

  • .mjs.jspackage.json 中的 "type": "module"
    • 不允许使用 CommonJS,例如,您不能使用 requiremodule.exportsexports
    • 导入时需要文件扩展名,例如,您应该使用 import './src/App.mjs' 而不是 import './src/App'(您可以使用 Rule.resolve.fullySpecified 禁用此强制执行)
  • .cjs.jspackage.json 中的 "type": "commonjs"
    • importexport 都不可用
  • .wasmpackage.json 中的 "type": "module"
    • 导入 wasm 文件时需要文件扩展名

ES6(推荐)

webpack 的第 2 版原生支持 ES6 模块语法,这意味着您可以使用 importexport,而无需像 babel 这样的工具来为您处理。请记住,您可能仍然需要 babel 来处理其他 ES6+ 功能。webpack 支持以下方法

import

静态地 import 另一个模块的 export

import MyModule from './my-module.js';
import { NamedExport } from './other-module.js';

您还可以 import 数据 URI

import 'data:text/javascript;charset=utf-8;base64,Y29uc29sZS5sb2coJ2lubGluZSAxJyk7';
import {
  number,
  fn,
} from 'data:text/javascript;charset=utf-8;base64,ZXhwb3J0IGNvbnN0IG51bWJlciA9IDQyOwpleHBvcnQgY29uc3QgZm4gPSAoKSA9PiAiSGVsbG8gd29ybGQiOw==';

export

将任何内容导出为default或命名导出。

// Named exports
export var Count = 5;
export function Multiply(a, b) {
  return a * b;
}

// Default export
export default {
  // Some data...
};

import()

function(string path):Promise

动态加载模块。对import()的调用被视为分割点,这意味着请求的模块及其子模块将被分割到一个单独的块中。

if (module.hot) {
  import('lodash').then((_) => {
    // Do something with lodash (a.k.a '_')...
  });
}

import() 中的动态表达式

无法使用完全动态的导入语句,例如import(foo)。因为foo可能潜在地是系统或项目中任何文件的任何路径。

import()必须包含至少一些有关模块位置的信息。捆绑可以限制在特定目录或一组文件中,以便在使用动态表达式时 - 每个可能在import()调用中请求的模块都包含在内。例如,import(`./locale/${language}.json`)将导致./locale目录中的每个.json文件都被捆绑到新的块中。在运行时,当变量language被计算后,任何类似english.jsongerman.json的文件都将可供使用。

// imagine we had a method to get language from cookies or other storage
const language = detectVisitorLanguage();
import(`./locale/${language}.json`).then((module) => {
  // do something with the translations
});

魔法注释

内联注释以使功能正常工作。通过在导入中添加注释,我们可以执行诸如命名块或选择不同模式之类的事情。有关这些魔法注释的完整列表,请参见下面的代码,然后是这些注释的作用说明。

// Single target
import(
  /* webpackChunkName: "my-chunk-name" */
  /* webpackMode: "lazy" */
  /* webpackExports: ["default", "named"] */
  /* webpackFetchPriority: "high" */
  'module'
);

// Multiple possible targets
import(
  /* webpackInclude: /\.json$/ */
  /* webpackExclude: /\.noimport\.json$/ */
  /* webpackChunkName: "my-chunk-name" */
  /* webpackMode: "lazy" */
  /* webpackPrefetch: true */
  /* webpackPreload: true */
  `./locale/${language}`
);
import(/* webpackIgnore: true */ 'ignored-module.js');
webpackIgnore

当设置为 true 时,禁用动态导入解析。

webpackChunkName

新块的名称。从 webpack 2.6.0 开始,给定字符串中支持占位符 [index][request],分别对应递增的数字或实际解析的文件名。添加此注释将导致我们的单独块命名为 [my-chunk-name].js 而不是 [id].js。

webpackFetchPriority
5.87.0+

为特定的动态导入设置 fetchPriority。也可以使用 module.parser.javascript.dynamicImportFetchPriority 选项为所有动态导入设置全局默认值。

import(
  /* webpackFetchPriority: "high" */
  'path/to/module'
);
webpackMode

从 webpack 2.6.0 开始,可以指定用于解析动态导入的不同模式。支持以下选项

  • 'lazy'(默认):为每个 import() 的模块生成一个懒加载块。
  • 'lazy-once':生成一个可以满足所有 import() 调用的单个懒加载块。该块将在第一次调用 import() 时获取,后续对 import() 的调用将使用相同的网络响应。请注意,这只有在部分动态语句的情况下才有意义,例如 import(`./locales/${language}.json`),其中可能请求多个模块路径。
  • 'eager':不生成额外的块。所有模块都包含在当前块中,不会进行额外的网络请求。仍然会返回一个 Promise,但它已经解析。与静态导入相比,模块不会在调用 import() 之前执行。
  • 'weak':如果模块函数已经以其他方式加载(例如,另一个块导入了它或包含该模块的脚本已加载),则尝试加载该模块。仍然会返回一个 Promise,但只有在块已经存在于客户端时才会成功解析。如果模块不可用,则 Promise 会被拒绝。永远不会执行网络请求。这在通用渲染中很有用,因为所需的块始终在初始请求中手动提供(嵌入在页面中),但在应用程序导航将触发未最初提供的导入的情况下则无效。
webpackPrefetch

告诉浏览器该资源可能在将来的某些导航中需要。查看指南以获取有关 webpackPrefetch 如何工作 的更多信息。

webpackPreload

告诉浏览器该资源可能在当前导航期间需要。查看指南以获取有关webpackPreload 工作原理的更多信息。

webpackInclude

在导入解析期间将与之匹配的正则表达式。只有匹配的模块将被捆绑

webpackExclude

在导入解析期间将与之匹配的正则表达式。任何匹配的模块将不会被捆绑

webpackExports:告诉 webpack 仅捆绑动态import() 模块的指定导出。它可以减小块的输出大小。从webpack 5.0.0-beta.18 开始可用。

CommonJS

CommonJS 的目标是为浏览器之外的 JavaScript 指定一个生态系统。以下 CommonJS 方法受 webpack 支持

require

require(dependency: String);

同步检索来自另一个模块的导出。编译器将确保依赖项在输出包中可用。

var $ = require('jquery');
var myModule = require('my-module');

也可以为 require 启用魔法注释,有关更多信息,请参见module.parser.javascript.commonjsMagicComments

require.resolve

require.resolve(dependency: String);

同步检索模块的 ID。编译器将确保依赖项在输出包中可用。建议将其视为不透明值,只能与 require.cache[id]__webpack_require__(id) 一起使用(最好避免此类用法)。

有关更多信息,请参见 module.id

require.cache

对同一模块的多次 require 操作只会导致一次模块执行和一次导出。因此,运行时存在一个缓存。从该缓存中删除值会导致新的模块执行和新的导出。

var d1 = require('dependency');
require('dependency') === d1;
delete require.cache[require.resolve('dependency')];
require('dependency') !== d1;
// in file.js
require.cache[module.id] === module;
require('./file.js') === module.exports;
delete require.cache[module.id];
require.cache[module.id] === undefined;
require('./file.js') !== module.exports; // in theory; in praxis this causes a stack overflow
require.cache[module.id] !== module;

require.ensure

require.ensure(
  dependencies: String[],
  callback: function(require),
  errorCallback: function(error),
  chunkName: String
)

将给定的 dependencies 分离到一个单独的包中,该包将异步加载。在使用 CommonJS 模块语法时,这是动态加载依赖项的唯一方法。这意味着,此代码可以在执行过程中运行,仅在满足特定条件时才加载 dependencies

var a = require('normal-dep');

if (module.hot) {
  require.ensure(['b'], function (require) {
    var c = require('c');

    // Do something special...
  });
}

以下参数按上述顺序支持

  • dependencies:一个字符串数组,声明 callback 中代码执行所需的所有模块。
  • callback:一个函数,webpack 将在依赖项加载完成后执行。一个 require 函数的实现作为参数传递给此函数。函数体可以使用它来进一步 require() 执行所需的模块。
  • errorCallback:一个函数,在 webpack 无法加载依赖项时执行。
  • chunkName:此特定 require.ensure() 创建的块的名称。通过将相同的 chunkName 传递给各种 require.ensure() 调用,我们可以将它们的代码合并到一个块中,从而只生成一个浏览器必须加载的包。

AMD

异步模块定义 (AMD) 是一个 JavaScript 规范,它定义了用于编写和加载模块的接口。webpack 支持以下 AMD 方法

define(带工厂方法)

define([name: String], [dependencies: String[]], factoryMethod: function(...))

如果提供了 dependencies,则将使用每个依赖项的导出(按相同顺序)调用 factoryMethod。如果未提供 dependencies,则将使用 requireexportsmodule(为了兼容性!)调用 factoryMethod。如果此函数返回一个值,则该值将由模块导出。编译器确保每个依赖项都可用。

define(['jquery', 'my-module'], function ($, myModule) {
  // Do something with $ and myModule...

  // Export a function
  return function doSomething() {
    // ...
  };
});

define(带值)

define(value: !Function)

这将导出提供的value。这里的value可以是任何东西,除了函数。

define({
  answer: 42,
});

require (amd-version)

require(dependencies: String[], [callback: function(...)])

类似于require.ensure,这将把给定的dependencies拆分成一个单独的包,该包将异步加载。callback将使用dependencies数组中每个依赖项的导出内容进行调用。

require(['b'], function (b) {
  var c = require('c');
});

带标签的模块

内部的LabeledModulesPlugin 允许您在模块中使用以下方法进行导出和导入

export label

导出给定的value。标签可以出现在函数声明或变量声明之前。函数名或变量名是导出值的标识符。

export: var answer = 42;
export: function method(value) {
  // Do something...
};

require label

使依赖项中的所有导出内容在当前作用域中可用。require标签可以出现在字符串之前。依赖项必须使用export标签导出值。无法使用 CommonJS 或 AMD 模块。

some-dependency.js

export: var answer = 42;
export: function method(value) {
  // Do something...
};
require: 'some-dependency';
console.log(answer);
method(...);

Webpack

除了上面描述的模块语法之外,webpack 还允许使用一些自定义的、特定于 webpack 的方法

require.context

require.context(
  (directory: String),
  (includeSubdirs: Boolean) /* optional, default true */,
  (filter: RegExp) /* optional, default /^\.\/.*$/, any file */,
  (mode: String) /* optional, 'sync' | 'eager' | 'weak' | 'lazy' | 'lazy-once', default 'sync' */
);

使用指向directory的路径、includeSubdirs选项、用于更细粒度控制包含模块的filter以及用于定义加载方式的mode来指定一组完整的依赖项。然后可以在稍后解析底层模块

var context = require.context('components', true, /\.html$/);
var componentA = context.resolve('componentA');

如果将mode设置为'lazy',则底层模块将异步加载。

var context = require.context('locales', true, /\.json$/, 'lazy');
context('localeA').then((locale) => {
  // do something with locale
});

所有可用模式及其行为的完整列表在import() 文档中描述。

require.include

require.include((dependency: String));

包含一个dependency,但不执行它。这可用于优化模块在输出块中的位置。

require.include('a');
require.ensure(['a', 'b'], function (require) {
  /* ... */
});
require.ensure(['a', 'c'], function (require) {
  /* ... */
});

这将导致以下输出

  • 入口块:file.jsa
  • 匿名块:b
  • 匿名块:c

如果没有require.include('a'),它将在两个匿名块中重复。

require.resolveWeak

类似于require.resolve,但不会将module拉入捆绑包。它被认为是“弱”依赖项。

if (__webpack_modules__[require.resolveWeak('module')]) {
  // Do something when module is available...
}
if (require.cache[require.resolveWeak('module')]) {
  // Do something when module was loaded before...
}

// You can perform dynamic resolves ("context")
// similarly to other require/import methods.
const page = 'Foo';
__webpack_modules__[require.resolveWeak(`./page/${page}`)];

警告

如果模块源包含无法静态分析的 require,则会发出关键依赖项警告。

示例代码

someFn(require);
require.bind(null);
require(variable);

10 位贡献者

skipjacksokrafadysamirsadekbyzykdebs-obrienwizardofhogwartsEugeneHlushkochenxsanjamesgeorge007WofWca