Entry
entry是配置模块的入口,webpack构建的第一步将从入口开始搜寻及遍历出所有入口依赖的模块,
entry是必填的,若不填则会导致webpack报错退出
context
webpack寻找文件的根目录,必须是一个绝对路径的字符串,还可以通过在启动 Webpack 时带上参数 webpack --context
来设置 context
,context
会影响到这些entry文件和依赖模块的相对路径所指向的真实文件。
entry的类型
string | './app/entry' | 入口模块的文件路径,可以是相对路径。 |
---|---|---|
array | ['./app/entry1', './app/entry2'] | 入口模块的文件路径,可以是相对路径。 |
object | { a: './app/entry-a', b: ['./app/entry-b1', './app/entry-b2']} | 配置多个入口,每个入口生成一个 Chunk |
如果是 array
类型,则搭配 output.library
配置项使用时,只有数组里的最后一个入口文件的模块会被导出。
Chunk
Webpack 会为每个生成的 Chunk 取一个名称,Chunk 的名称和 Entry 的配置有关:
- 如果
entry
是一个string
或array
,就只会生成一个 Chunk,这时 Chunk 的名称是main
; - 如果
entry
是一个object
,就可能会出现多个 Chunk,这时 Chunk 的名称是object
键值对里键的名称。
配置动态 Entry
// 同步函数
entry: () => {
return {
a:'./pages/a',
b:'./pages/b',
}
};
// 异步函数
entry: () => {
return new Promise((resolve)=>{
resolve({
a:'./pages/a',
b:'./pages/b',
});
});
};
Output
output
配置如何输出最终想要的代码。output
是一个 object
,里面包含一系列配置项,下面分别介绍它们。
filename
output.filename
配置输出文件的名称,为string 类型。 如果只有一个输出文件,则可以把它写成静态不变的
filename: 'bundle.js'
但是在有多个 Chunk 要输出时,就需要借助模版和变量了。前面说到 Webpack 会为每个 Chunk取一个名称,可以根据 Chunk 的名称来区分输出的文件名:
filename: '[name].js'
/**
*
id Chunk 的唯一标识,从0开始
name Chunk 的名称
hash Chunk 的唯一标识的 Hash 值
chunkhash Chunk 内容的 Hash 值
//其中 hash 和 chunkhash 的长度是可指定的,[hash:8] 代表取8位 Hash 值,默认是20位
/
代码里的 [name]
代表用内置的 name
变量去替换[name]
,这时你可以把它看作一个字符串模块函数, 每个要输出的 Chunk 都会通过这个函数去拼接出输出的文件名称
chunkFilename
指未被列在 entry
中,却又需要被打包出来的 chunk
文件的名称。一般来说,这个 chunk
文件指的就是要懒加载的代码
path
output.path
配置输出文件存放在本地的目录,必须是 string 类型的绝对路径。通常通过 Node.js 的 path
模块去获取绝对路径:
path: path.resolve(__dirname, 'dist_[hash]')
publicPath
output.publicPath
配置发布到线上资源的 URL 前缀,为string 类型。 默认值是空字符串 ''
,即使用相对路径。简而言之就是配置默认前缀
filename:'[name]_[chunkhash:8].js'
publicPath: 'https://cdn.example.com/assets/'
output.path
和 output.publicPath
都支持字符串模版,内置变量只有一个:hash
代表一次编译操作的 Hash 值
crossOriginLoading
output.crossOriginLoading
则是用于配置这个异步插入的标签的 crossorigin
值。
script 标签的 crossorigin 属性可以取以下值:
anonymous
(默认) 在加载此脚本资源时不会带上用户的 Cookies;use-credentials
在加载此脚本资源时会带上用户的 Cookies。
通常用设置 crossorigin 来获取异步加载的脚本执行时的详细错误信息。
libraryTarget 和 library
此配置的作用是控制 webpack 打包的内容是如何暴露的,用于解决打包后文件被使用时不同引入的兼容性.
output.library
配置导出库的名称。output.libraryTarget
配置以何种方式导出库, 是字符串的枚举类型,支持以下配置- var (默认) 当库(通过webpack打包后的文件)被加载时,那么库的返回值会被分配到使用用
var
申明的变量上,相当于直接一个全局变量,变量名为output.library - commonjs 通过 CommonJS 规范导出,在export对象上定义library设置的变量。在node中支持,浏览器中不支持。
- commonjs2,直接用module.export导出export,会忽略library设置的变量。在node中支持,在浏览器中不支持
- amd,在define方法上定义library设置的变量,不能用script直接引用,必须通过第三方模块RequireJS来时用
- umd,该方案支持commonjs、commonjs2、amd,可以在浏览器、node中通用。但是如果你想做到这一点,必须要额外设置,umdNamedDefine: true,globalObject: ‘this’,
- var (默认) 当库(通过webpack打包后的文件)被加载时,那么库的返回值会被分配到使用用
Module
module
配置如何处理模块,Webpack 把一切文件看作模块,CSS 文件也不例外,要引入 main.css
需要像引入 JavaScript 文件那样,因为 Webpack 不原生支持解析 CSS 文件。要支持非 JavaScript 类型的文件,需要使用 Webpack 的 Loader 机制
rules
rules
配置模块的读取和解析规则,通常用来配置 Loader。其类型是一个数组,数组里每一项都描述了如何去处理部分文件。 配置一项 rules
时大致通过以下方式
- 条件匹配:通过
test
、include
、exclude
三个配置项来命中 Loader 要应用规则的文件。 - 应用规则:对选中后的文件通过
use
配置项来应用 Loader,可以只应用一个 Loader 或者按照从后往前的顺序应用一组 Loader,同时还可以分别给 Loader 传入参数。 - 重置顺序:一组 Loader 的执行顺序默认是从右到左执行,通过
enforce
选项可以让其中一个 Loader 的执行顺序放到最前或者最后
module: {
rules: [
{
// 命中 JavaScript 文件
test: /\.js$/,
// 用 babel-loader 转换 JavaScript 文件
// ?cacheDirectory 表示传给 babel-loader 的参数,用于缓存 babel 编译结果加快重新编译速度
use: ['babel-loader?cacheDirectory'],
// 只命中src目录里的js文件,加快 Webpack 搜索速度
include: path.resolve(__dirname, 'src')
},
{
// 命中 SCSS 文件
test: /\.scss$/,
// 使用一组 Loader 去处理 SCSS 文件。
// 处理顺序为从后到前,即先交给 sass-loader 处理,再把结果交给 css-loader 最后再给 style-loader。
use: ['style-loader', 'css-loader', 'sass-loader'],
// 排除 node_modules 目录下的文件
exclude: path.resolve(__dirname, 'node_modules'),
},
{
// 对非文本文件采用 file-loader 加载
test: /\.(gif|png|jpe?g|eot|woff|ttf|svg|pdf)$/,
use: ['file-loader'],
},
]
}
在 Loader 需要传入很多参数时,你还可以通过一个 Object 来描述,例如在上面的 babel-loader 配置中有如下代码:
use: [
{
loader:'babel-loader',
options:{
cacheDirectory:true,
},
// enforce:'post' 的含义是把该 Loader 的执行顺序放到最后
// enforce 的值还可以是 pre,代表把 Loader 的执行顺序放到最前面
enforce:'post'
},
// 省略其它 Loader
]
上面的例子中 test include exclude
这三个命中文件的配置项只传入了一个字符串或正则,其实它们还都支持数组类型,使用如下:
{
test:[
/\.jsx?$/,
/\.tsx?$/
],
include:[
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'tests'),
],
exclude:[
path.resolve(__dirname, 'node_modules'),
path.resolve(__dirname, 'bower_modules'),
]
}
数组里的每项之间是或的关系,即文件路径符合数组中的任何一个条件就会被命中。
noParse
noParse
配置项可以让 Webpack 忽略对部分没采用模块化的文件的递归解析和处理,这样做的好处是能提高构建性能
noParse
是可选配置项,类型需要是 RegExp
、[RegExp]
、function
其中一个。
// 使用正则表达式noParse: /jquery|chartjs/// 使用函数,从 Webpack 3.0.0 开始支持noParse: (content)=> { // content 代表一个模块的文件路径 // 返回 true or false return /jquery|chartjs/.test(content);}
parser
配置模块化 JavaScript 的解析功能,parser
属性可以更细粒度的配置哪些模块语法要解析哪些不解析
module: { rules: [ { test: /\.js$/, use: ['babel-loader'], parser: { amd: false, // 禁用 AMD commonjs: false, // 禁用 CommonJS system: false, // 禁用 SystemJS harmony: false, // 禁用 ES6 import/export requireInclude: false, // 禁用 require.include requireEnsure: false, // 禁用 require.ensure requireContext: false, // 禁用 require.context browserify: false, // 禁用 browserify requireJs: false, // 禁用 requirejs } }, ]}
Resolve
Resolve 配置 Webpack 如何寻找模块所对应的文件,Webpack 内置 JavaScript 模块化语法解析功能,默认会采用模块化标准里约定好的规则去寻找,但你也可以根据自己的需要修改默认的规则
alias
resolve.alias
配置项通过别名来把原导入路径映射成一个新的导入路径。例如使用以下配置:
// Webpack alias 配置resolve:{ alias:{ components: './src/components/' }}//以上 alias 配置的含义是把导入语句里的 components 关键字替换成 ./src/components/。
当你通过 import Button from 'components/button'
导入时,实际上被 alias
等价替换成了 import Button from'./src/components/button'
resolve:{ alias:{ 'react$': '/path/to/react.min.js' }}//react$ 只会命中以 react 结尾的导入语句,即只会把 import 'react' 关键字替换成 import '/path/to/react.min.js'
mainFields
当从 npm 包中导入模块时(例如,import * as D3 from "d3"
),此选项将决定在 package.json
中使用哪个字段导入模块。根据 webpack 配置中指定的 target
不同,默认值也会有所不同
mainFields: ["module", "main"]//例如,D3 的 package.json 含有这些字段:{ ... main: 'build/d3.Node.js', browser: 'build/d3.js', module: 'index', ...}
这意味着当我们 import * as D3 from "d3"
,实际从 browser
属性解析文件。在这里 browser
属性是最优先选择的,因为它是 mainFields
的第一项。同时,由 webpack 打包的 Node.js 应用程序默认会从 module
字段中解析文件。
Webpack 会根据 mainFields
的配置去决定优先采用第三方模块的不同环境的代码,
//Webpack 会根据 mainFields 的配置去决定优先采用那份代码,mainFields 默认如下:mainFields: ['browser', 'main']
extensions
在导入语句没带文件后缀时,Webpack 会自动带上后缀后去尝试访问文件是否存在。 resolve.extensions
用于配置在尝试过程中用到的后缀列表,默认是:
extensions: ['.js', '.json']
也就是说当遇到 require('./data')
这样的导入语句时,Webpack 会先去寻找 ./data.js
文件,如果该文件不存在就去寻找 ./data.json
文件, 如果还是找不到就报错。
modules
resolve.modules
配置 Webpack 去哪些目录下寻找第三方模块,默认是只会去 node_modules
目录下寻找。 有时你的项目里会有一些模块会大量被其它模块依赖和导入,由于其它模块的位置分布不定,针对不同的文件都要去计算被导入模块文件的相对路径, 这个路径有时候会很长,就像这样 import '../../../components/button'
这时你可以利用 modules
配置项优化,假如那些被大量导入的模块都在 ./src/components
目录下,把 modules
配置成
modules:['./src/components','node_modules']//后,你可以简单通过 import 'button' 导入。
descriptionFiles
resolve.descriptionFiles
配置描述第三方模块的文件名称,也就是 package.json
文件。默认如下:
descriptionFiles: ['package.json']
enforceExtension
resolve.enforceExtension
如果配置为 true
所有导入语句都必须要带文件后缀, 例如开启前 import './foo'
能正常工作,开启后就必须写成 import './foo.js'
。
enforceModuleExtension
enforceModuleExtension
和 enforceExtension
作用类似,但 enforceModuleExtension
只对 node_modules
下的模块生效,enforceModuleExtension
通常搭配 enforceExtension
使用,在 enforceExtension:true
时,因为安装的第三方模块中大多数导入语句没带文件后缀, 所以这时通过配置 enforceModuleExtension:false
来兼容第三方模块。
Plugin
Plugin 是用来扩展 Webpack 功能的,通过在构建流程里注入钩子实现,它给 Webpack 带来了很大的灵活性。
配置 Plugin
plugins
配置项接受一个数组,数组里每一项都是一个要使用的 Plugin 的实例,Plugin 需要的参数通过构造函数传入
const CommonsChunkPlugin = require('webpack/lib/optimize/CommonsChunkPlugin');module.exports = { plugins: [ // 所有页面都会用到的公共代码提取到 common 代码块中 new CommonsChunkPlugin({ name: 'common', chunks: ['a', 'b'] }), ]};
DevServer
DevServer 会启动一个 HTTP 服务器用于服务网页请求,同时会帮助启动 Webpack ,并接收 Webpack 发出的文件更变信号,通过 WebSocket 协议自动刷新网页做到实时预览。
- 提供 HTTP 服务而不是使用本地文件预览;
- 监听文件的变化并自动刷新网页,做到实时预览;
- 支持 Source Map,以方便调试。
npm i -D webpack-dev-server
安装成功后执行 webpack-dev-server
命令, DevServer 就启动了
package.json增加script
"dev": "webpack-dev-server"
备注: "webpack-dev-server": "^3.11.2"+ "webpack-cli": "^3.3.12",
hot
devServer.hot
配置是否启用模块热替换功能。 DevServer 默认的行为是在发现源代码被更新后会通过自动刷新整个页面来做到实时预览,开启模块热替换功能后将在不刷新整个页面的情况下通过用新模块替换老模块来做到实时预览。
inline
DevServer 的实时预览功能依赖一个注入到页面里的代理客户端去接受来自 DevServer 的命令和负责刷新网页的工作。 devServer.inline
用于配置是否自动注入这个代理客户端到将运行在页面里的 Chunk 里去,默认是会自动注入。 DevServer 会根据你是否开启 inline
来调整它的自动刷新策略:
- 如果开启
inline
,DevServer 会在构建完变化后的代码时通过代理客户端控制网页刷新。 - 如果关闭
inline
,DevServer 将无法直接控制要开发的网页。这时它会通过 iframe 的方式去运行要开发的网页,当构建完变化后的代码时通过刷新 iframe 来实现实时预览。 但这时你需要去http://localhost:8080/webpack-dev-server/
实时预览你的网页了。
如果你想使用 DevServer 去自动刷新网页实现实时预览,最方便的方法是直接开启 inline
。
historyApiFallback
是否开启多页应用
对多页面进行配置
historyApiFallback: { // 使用正则匹配命中路由 rewrites: [ // /user 开头的都返回 user.html { from: /^\/user/, to: '/user.html' }, { from: /^\/game/, to: '/game.html' }, // 其它的都返回 index.html { from: /./, to: '/index.html' }, ]}
contentBase
devServer.contentBase
配置 DevServer HTTP 服务器的文件根目录。 默认情况下为当前执行目录,除非你有额外的文件需要被 DevServer 服务。 例如你想把项目根目录下的 public
目录设置成 DevServer 服务器的文件根目录,你可以这样配置:
devServer:{ contentBase: path.join(__dirname, 'public')}
headers
devServer.headers
配置项可以在 HTTP 响应中注入一些 HTTP 响应头,使用如下:
devServer:{ headers: { 'X-foo':'bar' }}
host
devServer.host
配置项用于配置 DevServer 服务监听的地址。 例如你想要局域网中的其它设备访问你本地的服务,可以在启动 DevServer 时带上 --host 0.0.0.0
。 host
的默认值是 127.0.0.1
即只有本地可以访问 DevServer 的 HTTP 服务
port
devServer.port
配置项用于配置 DevServer 服务监听的端口,默认使用 8080 端口。 如果 8080 端口已经被其它程序占有就使用 8081,如果 8081 还是被占用就使用 8082,以此类推。
allowedHosts
devServer.allowedHosts
配置一个白名单列表,只有 HTTP 请求的 HOST 在列表里才正常返回,使用如下:
allowedHosts: [ // 匹配单个域名 'host.com', 'sub.host.com', // host2.com 和所有的子域名 *.host2.com 都将匹配 '.host2.com']
https
DevServer 默认使用 HTTP 协议服务,它也能通过 HTTPS 协议服务。 有些情况下你必须使用 HTTPS,例如 HTTP2 和 Service Worker 就必须运行在 HTTPS 之上。 要切换成 HTTPS 服务,最简单的方式是:
devServer:{ https: true}
DevServer 会自动的为你生成一份 HTTPS 证书。如果你想用自己的证书可以这样配置:
devServer:{ https: { key: fs.readFileSync('path/to/server.key'), cert: fs.readFileSync('path/to/server.crt'), ca: fs.readFileSync('path/to/ca.pem') }}
open
devServer.open
用于在 DevServer 启动且第一次构建完时自动用你系统上默认的浏览器去打开要开发的网页。 同时还提供 devServer.openPage
配置项用于打开指定 URL 的网页。
Target
target
配置项可以让 Webpack 构建出针对不同运行环境的代码
target值 | 描述 |
---|---|
web | 针对浏览器 (默认),所有代码都集中在一个文件里 |
node | 针对 Node.js,使用 require 语句加载 Chunk 代码 |
async-node | 针对 Node.js,异步加载 Chunk 代码 |
webworker | 针对 WebWorker |
electron-main | 针对 Electron 主线程 |
electron-renderer | 针对 Electron 渲染线程 |
例如当你设置 target:'node'
时,源代码中导入 Node.js 原生模块的语句 require('fs')
将会被保留,fs
模块的内容不会打包进 Chunk 里。
Devtool
devtool
配置 Webpack 如何生成 Source Map,默认值是 false
即不生成 Source Map,想为构建出的代码生成 Source Map 以方便调试,可以这样配置:
module.export = { devtool: 'source-map'}
Watch 和 WatchOptions
Webpack 的监听模式,它支持监听文件更新,在文件发生变化时重新编译。在使用 Webpack 时监听模式默认是关闭的,想打开需要如下配置
module.export = { watch: true}
在使用 DevServer 时,监听模式默认是开启的。
除此之外,Webpack 还提供了 watchOptions
配置项去更灵活的控制监听模式,使用如下:
module.export = { // 只有在开启监听模式时,watchOptions 才有意义 // 默认为 false,也就是不开启 watch: true, // 监听模式运行时的参数 // 在开启监听模式时,才有意义 watchOptions: { // 不监听的文件或文件夹,支持正则匹配 // 默认为空 ignored: /node_modules/, // 监听到变化发生后会等300ms再去执行动作,防止文件更新太快导致重新编译频率太高 // 默认为 300ms aggregateTimeout: 300, // 判断文件是否发生变化是通过不停的去询问系统指定文件有没有变化实现的 // 默认每隔1000毫秒询问一次 poll: 1000 }}
Externals
Externals 用来告诉 Webpack 要构建的代码中使用了哪些不用被打包的模块,也就是说这些模版是外部环境提供的,Webpack 在打包时可以忽略它们。
有些 JavaScript 运行环境可能内置了一些全局变量或者模块,例如在你的 HTML HEAD 标签里通过以下代码:
<script src="path/to/jquery.js"></script>
通过 externals
可以告诉 Webpack JavaScript 运行环境已经内置了那些全局变量,针对这些全局变量不用打包进代码中而是直接使用全局变量。 要解决以上问题,可以这样配置 externals
:
module.export = { externals: { // 把导入语句里的 jquery 替换成运行环境里的全局变量 jQuery jquery: 'jQuery' }}
ResolveLoader
ResolveLoader 用来告诉 Webpack 如何去寻找 Loader,因为在使用 Loader 时是通过其包名称去引用的, Webpack 需要根据配置的 Loader 包名去找到 Loader 的实际代码,以调用 Loader 去处理源文件。
ResolveLoader 的默认配置如下:
module.exports = { resolveLoader:{ // 去哪个目录下寻找 Loader modules: ['node_modules'], // 入口文件的后缀 extensions: ['.js', '.json'], // 指明入口文件位置的字段 mainFields: ['loader', 'main'] }}
整体配置结构
const path = require('path');module.exports = { // entry 表示 入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。 // 类型可以是 string | object | array entry: './app/entry', // 只有1个入口,入口只有1个文件 entry: ['./app/entry1', './app/entry2'], // 只有1个入口,入口有2个文件 entry: { // 有2个入口 a: './app/entry-a', b: ['./app/entry-b1', './app/entry-b2'] }, // 如何输出结果:在 Webpack 经过一系列处理后,如何输出最终想要的代码。 output: { // 输出文件存放的目录,必须是 string 类型的绝对路径。 path: path.resolve(__dirname, 'dist'), // 输出文件的名称 filename: 'bundle.js', // 完整的名称 filename: '[name].js', // 当配置了多个 entry 时,通过名称模版为不同的 entry 生成不同的文件名称 filename: '[chunkhash].js', // 根据文件内容 hash 值生成文件名称,用于浏览器长时间缓存文件 // 发布到线上的所有资源的 URL 前缀,string 类型 publicPath: '/assets/', // 放到指定目录下 publicPath: '', // 放到根目录下 publicPath: 'https://cdn.example.com/', // 放到 CDN 上去 // 导出库的名称,string 类型 // 不填它时,默认输出格式是匿名的立即执行函数 library: 'MyLibrary', // 导出库的类型,枚举类型,默认是 var // 可以是 umd | umd2 | commonjs2 | commonjs | amd | this | var | assign | window | global | jsonp , libraryTarget: 'umd', // 是否包含有用的文件路径信息到生成的代码里去,boolean 类型 pathinfo: true, // 附加 Chunk 的文件名称 chunkFilename: '[id].js', chunkFilename: '[chunkhash].js', // JSONP 异步加载资源时的回调函数名称,需要和服务端搭配使用 jsonpFunction: 'myWebpackJsonp', // 生成的 Source Map 文件名称 sourceMapFilename: '[file].map', // 浏览器开发者工具里显示的源码模块名称 devtoolModuleFilenameTemplate: 'webpack:///[resource-path]', // 异步加载跨域的资源时使用的方式 crossOriginLoading: 'use-credentials', crossOriginLoading: 'anonymous', crossOriginLoading: false, }, // 配置模块相关 module: { rules: [ // 配置 Loader { test: /\.jsx?$/, // 正则匹配命中要使用 Loader 的文件 include: [ // 只会命中这里面的文件 path.resolve(__dirname, 'app') ], exclude: [ // 忽略这里面的文件 path.resolve(__dirname, 'app/demo-files') ], use: [ // 使用那些 Loader,有先后次序,从后往前执行 'style-loader', // 直接使用 Loader 的名称 { loader: 'css-loader', options: { // 给 html-loader 传一些参数 } } ] }, ], noParse: [ // 不用解析和处理的模块 /special-library\.js$/ // 用正则匹配 ], }, // 配置插件 plugins: [ ], // 配置寻找模块的规则 resolve: { modules: [ // 寻找模块的根目录,array 类型,默认以 node_modules 为根目录 'node_modules', path.resolve(__dirname, 'app') ], extensions: ['.js', '.json', '.jsx', '.css'], // 模块的后缀名 alias: { // 模块别名配置,用于映射模块 // 把 'module' 映射 'new-module',同样的 'module/path/file' 也会被映射成 'new-module/path/file' 'module': 'new-module', // 使用结尾符号 $ 后,把 'only-module' 映射成 'new-module', // 但是不像上面的,'module/path/file' 不会被映射成 'new-module/path/file' 'only-module$': 'new-module', }, alias: [ // alias 还支持使用数组来更详细的配置 { name: 'module', // 老的模块 alias: 'new-module', // 新的模块 // 是否是只映射模块,如果是 true 只有 'module' 会被映射,如果是 false 'module/inner/path' 也会被映射 onlyModule: true, } ], symlinks: true, // 是否跟随文件软链接去搜寻模块的路径 descriptionFiles: ['package.json'], // 模块的描述文件 mainFields: ['main'], // 模块的描述文件里的描述入口的文件的字段名称 enforceExtension: false, // 是否强制导入语句必须要写明文件后缀 }, // 输出文件性能检查配置 performance: { hints: 'warning', // 有性能问题时输出警告 hints: 'error', // 有性能问题时输出错误 hints: false, // 关闭性能检查 maxAssetSize: 200000, // 最大文件大小 (单位 bytes) maxEntrypointSize: 400000, // 最大入口文件大小 (单位 bytes) assetFilter: function(assetFilename) { // 过滤要检查的文件 return assetFilename.endsWith('.css') || assetFilename.endsWith('.js'); } }, devtool: 'source-map', // 配置 source-map 类型 context: __dirname, // Webpack 使用的根目录,string 类型必须是绝对路径 // 配置输出代码的运行环境 target: 'web', // 浏览器,默认 target: 'webworker', // WebWorker target: 'node', // Node.js,使用 `require` 语句加载 Chunk 代码 target: 'async-node', // Node.js,异步加载 Chunk 代码 target: 'node-webkit', // nw.js target: 'electron-main', // electron, 主线程 target: 'electron-renderer', // electron, 渲染线程 externals: { // 使用来自 JavaScript 运行环境提供的全局变量 jquery: 'jQuery' }, stats: { // 控制台输出日志控制 assets: true, colors: true, errors: true, errorDetails: true, hash: true, }, devServer: { // DevServer 相关的配置 proxy: { // 代理到后端服务接口 '/api': 'http://localhost:3000' }, contentBase: path.join(__dirname, 'public'), // 配置 DevServer HTTP 服务器的文件根目录 compress: true, // 是否开启 gzip 压缩 historyApiFallback: true, // 是否开发 HTML5 History API 网页 hot: true, // 是否开启模块热替换功能 https: false, // 是否开启 HTTPS 模式 }, profile: true, // 是否捕捉 Webpack 构建的性能信息,用于分析什么原因导致构建性能不佳 cache: false, // 是否启用缓存提升构建速度 watch: true, // 是否开始 watchOptions: { // 监听模式选项 // 不监听的文件或文件夹,支持正则匹配。默认为空 ignored: /node_modules/, // 监听到变化发生后会等300ms再去执行动作,防止文件更新太快导致重新编译频率太高 // 默认为300ms aggregateTimeout: 300, // 判断文件是否发生变化是不停的去询问系统指定文件有没有变化,默认每隔1000毫秒询问一次 poll: 1000 },}
多种环境配置
在运行 Webpack 时,会给这个函数传入2个参数,分别是:
env
:当前运行时的 Webpack 专属环境变量,env
是一个 Object。读取时直接访问 Object 的属性,设置它需要在启动 Webpack 时带上参数。例如启动命令是webpack --env.production --env.bao=foo
时,则env
的值是{"production":"true","bao":"foo"}
。argv
:代表在启动 Webpack 时所有通过命令行传入的参数,例如--config
、--env
、--devtool
,可以通过webpack -h
列出所有 Webpack 支持的命令行参数。
就以上配置文件而言,在开发时执行命令 webpack
构建出方便调试的代码,在需要构建出发布到线上的代码时执行 webpack --env.production
构建出压缩的代码。
配置总结
- 想让源文件加入到构建流程中去被 Webpack 控制,配置
entry
。 - 想自定义输出文件的位置和名称,配置
output
。 - 想自定义寻找依赖模块时的策略,配置
resolve
。 - 想自定义解析和转换文件的策略,配置
module
,通常是配置module.rules
里的 Loader。 - 其它的大部分需求可能要通过 Plugin 去实现,配置
plugin
。
babel配置
{ "presets": ["@vue/app"]}
- .babelrc相当于babel的拓展配置,babel在执行编译的过程中,会从项目的根目录.babelrc文件中读取配置
- .babelrc是一个json格式的文件,在.babelrc配置文件中,主要是对预设(presets) 和 插件(plugins) 进行配置,
- plugins 该属性是告诉babel要使用那些插件,这些插件可以控制如何转换代码。
- Babel默认只转换新的javascript语法,而不转换新的API,比如 Iterator, Generator, Set, Maps, Proxy, Reflect,Symbol,Promise 等全局对象。以及一些在全局对象上的方法(比如 Object.assign)都不会转码。
babel-runtime 它是将es6编译成es5去执行。我们使用es6的语法来编写,最终会通过babel-runtime编译成es5.也就是说,不管浏览器是否支持ES6,只要是ES6的语法,它都会进行转码成ES5.所以就有很多冗余的代码。
import Promise from 'babel-runtime/core-js/promise'//这样不仅避免污染全局对象,而且可以减少不必要的代码。
babel-polyfill 它是通过向全局对象和内置对象的prototype上添加方法来实现的。比如运行环境中不支持Array.prototype.find 方法,引入polyfill, 我们就可以使用es6方法来编写了,但是缺点就是会造成全局空间污染。
babel-plugin-transform-runtime
{ 'plugins': [ [ 'transform-runtime', { 'helpers': false, 'polyfill': false, 'regenerator': true, 'moduleName': 'babel-runtime' } ] ]}
- **helpers: 默认值为true,**表示是否开启内联的babel helpers(即babel或者环境本来存在的某些对象方法函数)如:extends,etc这样的 在调用模块名字时将被替换名字。
- polyfill:默认值为true,表示是否把内置的东西(Promise, Set, Map)等转换成非全局污染的。
- **regenerator:默认值为true,**是否开启generator函数转换成使用regenerator runtime来避免污染全局域。
- **moduleName:默认值为 babel-runtime,**当调用辅助 设置模块(module)名字/路径.
- presets 告诉 Babel要转换的源码使用了哪些新的语法特性,presets是一组Plugins的集合。
本来一个版本的js语法,有多个plugin插件,但是Babel团队为了方便,将同属ES2015的几十个Transform Plugins集合到babel-preset-es2015一个Preset中,这样我们只需要在.babelrc的presets加入es2015一个配置就可以完成全部ES2015语法的支持了:
// .babelrc{ "presets": [ "es2015" ]}
随着时间的推移,babel的版本会有很对,于是babel-preset-env 出现了,它的功能类似于 babel-preset-latest,它会根据目标环境选择不支持的新特性来转译
首先需要在项目中安装,如下命令:
npm install babel-preset-env --save-dev
{ "presets": ['env']}
如果需要支持每个浏览器最后两个版本和safari大于等于7版本所需的polyfill代码转换,我们可以如下配置:
{ 'presets': [ ['env', { 'target': { 'browsers': ['last 2 versions', 'safari >= 7'] } }] ]}
理解 babel-preset-env 中的选项配置:
- targets: {[string]: number | string }, 默认为{}; 含义是支持一个运行环境的对象,比如支持node版本;
- targets.browsers <Array | string> 支持浏览器的配置项,该配置项使用方式可以到 browserslist来查询
- modules 该参数的含义是:启用将ES6模块语法转换为另一种模块类型。将该设置为false就不会转换模块 ,默认commonjs
- loose, 该参数值默认为false。 含义是:允许它们为这个 preset 的任何插件启用”loose” 转换。
- include: 包含一些插件,默认为 []; 比如包含箭头函数,
- exclude; 排除哪些插件,默认为 [];
安装webpack
现在默认是4.0版本 我的笔记是4.0以下的版本 可以在npm安装指定
npm i webpack@3.8 -S
安装webpack或者less最好不要安装全局的,否则可能会导致webpack的版本差异
-
在package.json 中配置一个脚本,这个脚本,这个脚本用的命令是webpack.
-
"scripts": { "build": "webpack",},
-
会去当前的node_modules下找bin对应的webpack名字 让其执行,执行的就是bin/webpack.js,
-
webpack.js需要当前目录下有个名字叫webpack.config.js的文件,
-
我们通过npm run build执行的目录是当前文件的夹的目录 所以会去当前目录下查找
webpack.config.js 打包配置
// webpack必须采用commonjs写法let path = require('path'); // 专门处理路径用的模块 // 以当前路径 解析出一个相对路径 // path.resolve('./dist')module.exports = { entry:'./src/main.js', //打包的入口文件,webpack会自动查找相关的依赖进行打包,需要打包的文件 output:{ filename:'bundle.js', //打包后的名字 path:path.resolve('./dist') //必须是绝对路径 打包的文件放在哪里 }}
写法固定
需要打包多个就在entry写一个对象 写多个入口,出口写数组
entry:{main:'.xx',main2:'xxx'} ----------------------------------- filename:'[name,name2].js'
打包命令 -> npm run build
1.解决模块问题 将多个模块打包到一个文件,且不需要管各种模块规范
es6转es5
babel 转义es6 -> es5
安装babel
npm install babel-core --save-dev ->babel核心npm install babel-loader --save-dev ->解析模块
配置bable-loader ->webpack.config.js
//模块的解析规则 // - js 匹配所以的js 用babel-loader 进行转义 排除掉node_modules module:{ rules:[ {test:/\.js$/,use:'babel-loader',exclude:/node_modules/} //使用正则进行文件匹配 ] }
安装前面两个还是不能进行转义,需要安装babel-preset-es2015 进行 预设 告诉loader拥有解析es6的语法
安装 npm i babel-preset-es2015 --save-dev
在当前目录新建一个文件 名称固定 -> .babelrc
{ "presets": ["es2015"]}
解析es2017 语法
先下载es2017的插件
npm i babel-preset-stage-0 --save-dev
然后再.babelrc配置
{ "presets": ["es2015","stage-0"]}
解析css样式
引入css文件,这样引入会操作 webpack解析不了
import './xxx.css' ->这样引入不识别
需要先下载插件 ,
npm i css-loader --save-dev -> 将css解析成模块 npm i style-loader --save-dev -> 将解析的内容插入到style标签内
然后在webpack.config.js 配置规则
在rules加一个对象//use的是 从右往左写 {test:/\.css$/,use:['style-loader','css-loader']}
css预处理语言 -> less,sass,stylus
less-loader -> less css-loader -> style-loader sass-loader stylus-loader
安装 less-loader 和 less
npm i less less-loader --save-dev
配置rules ->webpack.config.js
{test:/\.less$/,use:['style-loader','css-loader','less-loader']}
解析图片
file-loader url-loader //使用这个 是依赖于file-loader的 会自动调用,但是都要下
npm i file-loader url-loader --save-dev
添加配置,默认情况下图片都会转为base-64,我可以设置 ?limit=8192
表示转化base-64只在8192字节以下转化,其他情况输出图片
{test:/\.(jpg|png|gif)$/,use:'url-loader?limit=8192'},
直接写图片url js不会把它当做url 而是会当做字符解析,需要通过url-loader解析
img.src = './1.jpg' -> 属性值是一个字符串,回当字符串解析
自动新建html并引入文件
插件的作用 是以我们自己的html为模板,将打包后的结果,自动引入html中,传出到dist目录下.
npm i html-webpack-plugin --save-dev
这个是插件,需要在配置文件中引入
let HtmlWebpackPlugin = require('html-webpack-plugin');
然后再配置
plugins:[ new HtmlWebpackPlugin({ template:'./src/index.html', //设置生成后的文件的以谁为模板,而且html模板还会自动引入生的js文件 filename:'login.html' //产出文件的名称 })]
这里面内置了一个服务,可以帮我们启动一个端口号,当代码更新时,可以自动打包(不产生实体文件,在内存中),代码有变化就重新执行
npm i webpack-dev-server --save-dev
在package.json 配置脚本
"scripts": { "build": "webpack", "dev": "webpack-dev-server"},
然后就可以执行npm run dev ->运行这个内置服务器
如果你的webpack版本是3.6以上 的,webpack-dev-server就只能装2.x的,不然会报错
版本不兼容产生的错误代码D:\myProjectDemos\webpackDemo\node_modules\ajv-keywords\keywords\instanceof.js:52 throw new Error('invalid "instanceof" keyword value ' + c); ^ Error: invalid "instanceof" keyword value Promise
如果没问题就会开启内置服务器监听端口号 8080,默认是打开index.html
npm run dev 启动内置服务器-----------------------------Project is running at http://localhost:8080/
浏览器输入http://localhost:8080/ 打开的就是index.html这个页面 不需要设置路由
webpack的基本配置就完事了
eslint配置
ESlint 配置文件 .eslintrc
,该文件格式为 JSON。
{ // 从 eslint:recommended 中继承所有检查规则 "extends": "eslint:recommended", // 再自定义一些规则 "rules": { // 需要在每行结尾加 ; "semi": ["error", "always"], // 需要使用 "" 包裹字符串 "quotes": ["error", "double"] }}
eslint-loader 可以方便的把 ESLint 整合到 Webpack 中,使用方法如下:
module.exports = { module: { rules: [ { test: /\.js$/, // node_modules 目录的下的代码不用检查 exclude: /node_modules/, loader: 'eslint-loader', // 把 eslint-loader 的执行顺序放到最前面,防止其它 Loader 把处理后的代码交给 eslint-loader 去检查 enforce: 'pre', }, ], },}
如果你的项目是使用 Git 管理,Git 提供了 Hook 功能能做到在提交代码前触发执行脚本。
安装 husky 时,husky 会通过 Npm Script Hook 自动配置好 Git Hook,你需要做的只是在 package.json
文件中定义几个脚本,方法如下:
{ "scripts": { // 在执行 git commit 前会执行的脚本 "precommit": "npm run lint", // 在执行 git push 前会执行的脚本 "prepush": "lint", // 调用 eslint、stylelint 等工具检查代码 "lint": "eslint && stylelint" }}
个人心得
首先是webpack只能解析js文件文件,所以所有其他类型的文件都需要对应的loader进行转译,将不同后缀的文件,转译为.js的文件,这个过程就需要在webpack.config.js配置, module下的rules规则.
{ module:{ rules:[ { test:/\.js$/, //匹配js后缀, use:['babel-loader'], //使用bebel-loader进行翻译 ,因为可能存在不同版本的js 语法 相互转换, include:path, //对那一部分文件进行处理 exclude:path, //不处理那些文件 }, { test:/\.css$/, use:['style-loader','css-loader'] //解析顺序 从右往左 依次使用loader对文件进行解析 } ] }}