Module
Webpack的构建就是从入口文件开始对项目中所涉及到的多类型模块进行处理,其处理是按照一定规则进行的,Module选型就是告诉Webpack如何处理项目中不同类型的模块。
NoParse
Webpack会对项目中所涉及到的模块进行解析和编译,这里的模块通常是按照某种模块化标准生成的,如果项目中所依赖的模块或者第三方库是没有采用模块化的,例如JQuery,Loadsh等等。那么Webpack解析和编译这些模块是没有任何意义的,反而会增加构建时间,降低构建效率。
通过对noParse进行配置,就可以让Webpack取消对相关Library的处理:
module.exports = {
/* 其他配置 */
module: {
noParse: /jquery|lodash/,
}
}
这里使用正则匹配相关Lbrary,当Webpack遇到这些library时候,就会避开对该library的解析和处理。noParser还可以配置成函数,实现更精细化的配置:
module.exports = {
/* 其他配置 */
module: {
noParse: function (content) {
return /jquery|lodash/.test(content);
}
}
}
值得注意的是,忽略的模块文件中不应该含有 import, require, define 这些模块化相关语句的调用,或任何其他导入机制,不然浏览器是无法直接运行相关模块化语句。
Rules
Webpack默认能够识别处理的模块是以.js和.json为文件后缀名的模块。对其他类型的模块解析和编译需要在Rules中配置相关的Loader。比如使用Babel-loader去转换ES6,Css-loader去处理Css代码等等。
Rules规定了相关模块的读取和解析规则,通常用于配置Loader。Rules的类型是一个数组,所以可以在Rules中进行多种模块读取和解析规则的配置。配置一项Rules时大致可以分为以下三个步骤来进行:
- 条件匹配:通过test,include,exclude三个配置来选中Loader要处理的文件。(为了性能,一般推荐使用include来精确需要处理的目录位置)
- 应用规则:选中的文件通过use的配置来决定采用哪种Loader进行解析处理。对文件进行解析的时候可以采用一个Loader,还可以采用一组Loader的组合。
- 重置顺序:一组Loader的默认执行顺序是从右到左,从下到上。可以通过Enforce将某一个Loader的执行顺序放到最前或者最后。
例如对于使用Less所编写的样式模块,可以采用如下配置,去解析编译:
module.exports = {
/* 其他配置 */
module: {
rules: [
{
// 匹配要处理的文件
test: /\.less$/,
// 只匹配src文件夹中的less文件
include: path.resolve(__dirname, 'src'),
// 忽略node_modules中的css文件
exclude: path.resolve(__dirname, 'node_modules'),
// 配置使用的loader
use: [
'style-loader',
{
loader: 'css-loader',
// 给loader传入相关的选项
options: {
modules: true
}
},
'less-loader'
]
}
]
}
}
Parser
使用Parser可以使相关Loader对不同类型的文件进行更精细化的处理。
- 将选项设置为false,将禁用解析器。
- 将选项设置为true,或不修改将其保留为undefined,可以启用解析器。
然而,一些解析器(parser)插件可能不光只接收一个布尔值:
module.exports = {
/* 其他配置 */
module: {
rules: [
{
test: /.js$/,
use: ['babel-loader'],
parser: {
// 禁用 AMD
amd: false,
// 禁用 CommonJS
commonjs: false,
// 禁用 SystemJS
system: false,
// 禁用 ES2015 Harmony import/export
harmony: false,
// 禁用 require.include
requireInclude: false,
// 禁用 require.ensure
requireEnsure: false,
// 禁用 require.context
requireContext: false,
// 禁用特殊处理的 browserify bundle
browserify: false,
// 禁用 requirejs.*
requireJs: false,
// 禁用 __dirname, __filename, module, require.extensions, require.main 等。
node: false,
// 在模块级别(module level)上重新配置 node 层(layer)
node: { /** ... */ }
}
}
]
}
}
本章节提供案例源码下载:https://gitee.com/mvc_ydb/webpack/blob/master/module.zip
Resolve
Module规定了如何处理项目中涉及到的模块,侧重的是解析和编译过程,而Resolve规定了项目中的涉及到的模块路径如何被解析,侧重的是模块使用路径相关过程。
Webpack对Resolve提供默认值,但是在不同项目需求中还是可能会修改一些解析的细节。
Alias
在项目中引入相关模块会使用大量的import或require这些模块化引入语句,有的时候所引入的模块可能有多个层级,导致其引入路径非常长。使用Alias可以给import或require引入的模块创建引用路径的映射,在项目代码中方便相关的模块引入:
module.exports = {
/* 其他配置 */
resolve: {
alias: {
Utils: path.resolve(__dirname, 'src/utils/'),
}
}
}
这里使用Utils来作为./src/utils/的别名,只需所示方式即可引入相关模块:import {…} from ‘Utils’;
还可以在别名后面加上$符号实现精确的匹配:
module.exports = {
/* 其他配置 */
resolve: {
alias: {
Utils$: path.resolve(__dirname, 'src/utils/date.js'),
}
}
}
MainFields
很多模块会编写多份代码来在不同环境下使用,模块的包信息文件package.json中记录来模块在各种环境下的入口文件的地址。当从 npm 包中导入这类模块时(例如,import * as Module from “Render”),MainFields决定使用package.json中的哪个字段导入模块。根据 Webpack配置中指定的target不同,默认值也会有所不同。假如Render模块对应的package.json中关于入口文件的声明代码描述如下:
{
"main": "index.js",
"module": "node/index.js",
"jsnext:main": "es6/index.js"
}
module表示Node.js环境使用的代码入口文件,main表示采用ES5语法的代码入口文件,jsnext:main表示采用ES6语法的代码入口文件。Webpack会根据MainFields的配置决定优先采用哪份代码。
给target设置不同的值,会给MainFields赋予不同的默认值:
- 当target属性设置为 webworker, web 或者没有指定,默认值为:mainFields: [“browser”, “module”, “main”]
- 对于其他任意的target(包括 node),默认值为:mainFields: [“module”, “main”]
想优先使用采用ES6语法编写的代码,则可所示方式配置即可:mainFields: [“jsnext:main”, “main”,…]。
Extensions
项目中书写相关模块的引入语句的时候,可以省略模块文件的后缀名称:import {getSecond} from ‘date’;在这里引入date模块的时候是没有添加文件后缀的,在构建过程中Webpack会自动带上后缀去尝试访问文件是否存在。Extensions用于配置可能用到的后缀名列表,其默认值为:extensions: [‘js’,‘json’]。
当你使用TypeScript开发你的项目的时候,希望Webpack优先使用项目下的TypeScript文件:
module.exports = {
/* 其他配置 */
resolve: {
/* 其他配置 */
extensions: ['.ts', '.js', '.json']
}
}
构建的时候,Webpack对于没有带文件后缀的模块引入的时候,就会优先使用.ts文件后缀去寻找对应的文件是否存在,不存在的话,使用.js文件后缀在去寻找,如果还是没有找到,就会使用.json文件后缀去寻找。当Extensions中所有的文件后缀都没有匹配到的时候,那么Webpack会抛出相关的错误,此次构建失败。根据项目需求,合理设置extensions可以加速构建。
Modules
Modules告诉了Webpack解析模块时应该搜索的目录。默认值为modules: [“node_modules”],表示通过Npm下载的模块在其被进引入使用的时候,Webpack就会去node_modules中寻找,如果当前目录下的node_modules没有找到,就会父级目录下的node_modules中去寻找,以此类推。当确定只在当前目录下的node_modules中寻找的时候,可以做如下配置:
module.exports = {
/* 其他配置 */
resolve: {
modules: [path.resolve(__dirname, "node_modules")]
}
}
来减少搜索时间。
如果项目需要使用本地编写的模块,比如编写的UI模块:
import '../../MyUI/Button';
可做如下配置,简化模块引入语句:
module.exports = {
/* 其他配置 */
resolve: {
modules: ['../../MyUI', 'node_modules']
}
}
引入代码修改为:
import 'Button';
Webpack会优先去MyUI文件目录去寻找,没有找到再去node_modules文件目录下去寻找。
EnforceExtension
EnforceExtension表示引入文件的时候是否需要加上文件后缀名,默认值为false,如果设置为true,则引入文件的时候必须要加上文件后缀名。