本节涵盖了使用 webpack 编译的代码中所有可用的方法。当使用 webpack 打包您的应用程序时,您可以从多种模块语法风格中选择,包括 ES6、CommonJS 和 AMD。
虽然 webpack 支持多种模块语法,但我们建议遵循单一语法以保持一致性并避免奇怪的行为/错误。实际上,webpack 会针对 .mjs
文件、.cjs
文件或 .js
文件强制执行此建议,前提是它们最近的父级 package.json
文件包含一个 "type"
字段,其值为 "module"
或 "commonjs"
。在继续阅读之前,请注意这些强制执行。
.mjs
或 .js
且 package.json
中的 "type": "module"
require
、module.exports
或 exports
import './src/App.mjs'
而不是 import './src/App'
(您可以使用 Rule.resolve.fullySpecified
禁用此强制执行).cjs
或 .js
且 package.json
中的 "type": "commonjs"
import
和 export
都不可用.wasm
且 package.json
中的 "type": "module"
webpack 的第 2 版原生支持 ES6 模块语法,这意味着您可以使用 import
和 export
,而无需像 babel 这样的工具来为您处理。请记住,您可能仍然需要 babel 来处理其他 ES6+ 功能。webpack 支持以下方法
静态地 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==';
将任何内容导出为default
或命名导出。
// Named exports
export var Count = 5;
export function Multiply(a, b) {
return a * b;
}
// Default export
export default {
// Some data...
};
function(string path):Promise
动态加载模块。对import()
的调用被视为分割点,这意味着请求的模块及其子模块将被分割到一个单独的块中。
if (module.hot) {
import('lodash').then((_) => {
// Do something with lodash (a.k.a '_')...
});
}
无法使用完全动态的导入语句,例如import(foo)
。因为foo
可能潜在地是系统或项目中任何文件的任何路径。
import()
必须包含至少一些有关模块位置的信息。捆绑可以限制在特定目录或一组文件中,以便在使用动态表达式时 - 每个可能在import()
调用中请求的模块都包含在内。例如,import(`./locale/${language}.json`)
将导致./locale
目录中的每个.json
文件都被捆绑到新的块中。在运行时,当变量language
被计算后,任何类似english.json
或german.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
为特定的动态导入设置 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 的目标是为浏览器之外的 JavaScript 指定一个生态系统。以下 CommonJS 方法受 webpack 支持
require(dependency: String);
同步检索来自另一个模块的导出。编译器将确保依赖项在输出包中可用。
var $ = require('jquery');
var myModule = require('my-module');
也可以为 require
启用魔法注释,有关更多信息,请参见module.parser.javascript.commonjsMagicComments
。
require.resolve(dependency: String);
同步检索模块的 ID。编译器将确保依赖项在输出包中可用。建议将其视为不透明值,只能与 require.cache[id]
或 __webpack_require__(id)
一起使用(最好避免此类用法)。
有关更多信息,请参见 module.id
。
对同一模块的多次 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(
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) 是一个 JavaScript 规范,它定义了用于编写和加载模块的接口。webpack 支持以下 AMD 方法
define([name: String], [dependencies: String[]], factoryMethod: function(...))
如果提供了 dependencies
,则将使用每个依赖项的导出(按相同顺序)调用 factoryMethod
。如果未提供 dependencies
,则将使用 require
、exports
和 module
(为了兼容性!)调用 factoryMethod
。如果此函数返回一个值,则该值将由模块导出。编译器确保每个依赖项都可用。
define(['jquery', 'my-module'], function ($, myModule) {
// Do something with $ and myModule...
// Export a function
return function doSomething() {
// ...
};
});
define(value: !Function)
这将导出提供的value
。这里的value
可以是任何东西,除了函数。
define({
answer: 42,
});
require(dependencies: String[], [callback: function(...)])
类似于require.ensure
,这将把给定的dependencies
拆分成一个单独的包,该包将异步加载。callback
将使用dependencies
数组中每个依赖项的导出内容进行调用。
require(['b'], function (b) {
var c = require('c');
});
内部的LabeledModulesPlugin
允许您在模块中使用以下方法进行导出和导入
导出给定的value
。标签可以出现在函数声明或变量声明之前。函数名或变量名是导出值的标识符。
export: var answer = 42;
export: function method(value) {
// Do something...
};
使依赖项中的所有导出内容在当前作用域中可用。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 的方法
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((dependency: String));
包含一个dependency
,但不执行它。这可用于优化模块在输出块中的位置。
require.include('a');
require.ensure(['a', 'b'], function (require) {
/* ... */
});
require.ensure(['a', 'c'], function (require) {
/* ... */
});
这将导致以下输出
file.js
和 a
b
c
如果没有require.include('a')
,它将在两个匿名块中重复。
类似于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);