该思惟导图是根据<<深刻浅出webpack>>
章节大纲总结出来的。经过阅读这本书梳理webpack所包含的知识点,了解了webpack(版本为4.X)的相关配置,以及loader和plugin的原理以及编写。思惟导图可以很形象的描述出各知识点之间的关系,同时也能加深知识点在咱们心中的印象。画此思惟导图的目的也是为了供之后本身复习用的。javascript
3.1 Entrycss
构建的入口,Webpack 执行构建的第一步将从 Entry 开始,可抽象成输入。经过搜寻及递归找出全部入口所依赖的模块。Entry 主要有 String、Array 和 Object 三种类型。若是为 Array 类型时,搭配 output.library 配置项使用时,只有数组里的最后一个入口文件的模块会被导出。html
module.exports={
entry:'./app/entry', //入口模块的文件路径,能够是相对路径。
entry:['./app/entry1', './app/entry2'],//入口模块的文件路径,能够是相对路径。只有1个入口,两个入口文件
entry:{
a: './app/entry-a', b: ['./app/entry-b1', './app/entry-b2']
//配置多个入口,每一个入口生成一个 Chunk。两个入口。
},
}
复制代码
有时候因为项目须要,可能须要构建多个页面入口。除了上面的静态页面入口配置,还能够动态配置页面入口。通常有以下两种方式。前端
//同步函数
entry: () => {
return {
index: "@/pages/index",
user: "@pages/user"
};
};
//异步函数
entry: () => {
return new Promise((resolve)=>{
resolve({
a:'./pages/a',
b:'./pages/b',
});
});
};
复制代码
3.2 Output:vue
配置如何输出最终想要的代码。output 是一个 object,里面包含一系列配置项,下面分别介绍它们。java
module.exports={
...
output:{
//若是只有一个输出文件,则能够把它写成静态不变的。
filename:'bundle.js',
//多个 Chunk 要输出时,能够根据 Chunk 的名称来区分输出的文件名
filename: '[name].js',//能够将[name]当作字符串模板函数。该name为内置的哈希值。
chunkFilename:[name].js,
path: path.resolve(__dirname, 'dist');
publicPath:'https://cdn.example.com/assets/',
libraryTarget:var
}
}
复制代码
内置变量主要有如下这些:node
3.3 Modulereact
模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出全部依赖的模块。主要有这些配置项。jquery
module.exports={
...
module:{
//让 Webpack 忽略对部分没采用模块化的文件的递归解析和处理。
noParse: /jquery|chartjs/
// 从 webpack 3.0.0 开始,也能够是函数
noParse: function(content) {
return /jquery|lodash/.test(content);
},
rules:[
{
test: /\.js$/,//转码执行后缀的文件,通常是正则表达式。可为数组
use: ['babel-loader?cacheDirectory'],//?cacheDirectory 表示传给 babel-loader 的参数,用于缓存 babel 编译结果加快从新编译速度。是loader 属性的简写方式.(如:use: [ { loader: "style-loader "} ])。
include:path.resolve(__dirname,"src"),//只命中src文件夹下的就是文件。可为数组
//解析选项对象。能够更细粒度的配置哪些模块语法要解析哪些不解析
parser:{
amd: false, // 禁用 AMD
commonjs: false, // 禁用 CommonJS
system: false, // 禁用 SystemJS
harmony: false, // 禁用 ES2015 Harmony import/export
requireInclude: false, // 禁用 require.include
requireEnsure: false, // 禁用 require.ensure
requireContext: false, // 禁用 require.context
browserify: false, // 禁用特殊处理的 browserify bundle
requireJs: false, // 禁用 requirejs.*
node: false, // 禁用 __dirname, __filename, module, require.extensions, require.main 等。
node: {...} // 在模块级别(module level)上从新配置 node 层(layer)
},
exclude:path.resolve(__dirname,'node_modules'),//排除node_module文件夹下的js文件。可为数组。
},
{
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'),
},
{
test: /\.js$/
use:[
loader:'babel-loader',
//在 Loader 须要传入不少参数时,你还能够经过一个 Object 来描述。
options:{
cacheDirectory:true,
},
// enforce:'post' 的含义是把该 Loader 的执行顺序放到最后。 enforce 的值还能够是 pre,表明把 Loader 的执行顺序放到最前面
enforce:'post'
]
},
//loader还能够采用链式写法。loader从右到左的被调用
{
test:/\.css$/
use: [
'style-loader',
{
loader: 'css-loader',
//
options: {
importLoaders: 1
}
},
{
loader: 'less-loader',
options: {
noIeCompat: true
}
}
]
}
]
}
}
复制代码
3.4 Resolvewebpack
Resolve 配置 Webpack 如何寻找模块所对应的文件。设置模块如何被解析。
module.exports={
...
resolve:{
//经过别名来把原导入路径映射成一个新的导入路径
alias:{
'components': './src/components/',
'@':"./src",
~:"./src",
'vue$': 'vue/dist/vue.esm.js',
}
//指定一个字段,例如 browser(浏览器环境),根据此规范进行解析。只会使用找到的第一个
aliasFields:['browser', 'main']
descriptionFiles:["package.json"],//描述文件
enforceExtension:false,//是否强制扩展名
extensions:[".js",".json"],//自动解析的扩展,导入语句没带文件后缀时,Webpack 会自动带上后缀后去尝试访问文件是否存在.
modules:['./src/components','node_modules'],//告诉 webpack 解析模块时应该搜索的目录。绝对路径和相对路径都能使用。
}
}
复制代码
3.5 Plugins
用于以各类方式自定义 webpack 构建过程。经过在webpack构建过程当中,经过在特定的事件阶段,注入相应的逻辑来达到想要的效果。
module.exports={
...
plugins:[
// 显示出被替换模块的名称
new NamedModulesPlugin(),
//定义全局环境变量的值
new DefinePlugin({
// 定义 NODE_ENV 环境变量为 production
'process.env': {
NODE_ENV: JSON.stringify('production')
}
}),
//清除文件夹(在打包时使用)
new CleanWebpackPlugin(['dist']),
//生成模板文件,生成默认开始页面的文件,默认为index.html
new HtmlWebpackPlugin({
title: 'Output Management',
filename:"index.html",
template:"index.html",
inject:true,//将全部的资源注入到template指定的index.html中。
}),
//压缩代码(只在生产环境下使用)
new UglifyJSPlugin({
cache:true,//是否使文件缓存
parallel: true,//并行压缩代码
sourceMap:true,//是否为打包后的代码生成源码
compress: {
// 在UglifyJs删除没有用到的代码时不输出警告
warnings: false,
// 删除全部的 `console` 语句,能够兼容ie浏览器
drop_console: true,
// 内嵌定义了可是只用到一次的变量
collapse_vars: true,
// 提取出出现屡次可是没有定义成变量去引用的静态值
reduce_vars: true,
dead_code:true,//删除无用代码
},
output: {
// 最紧凑的输出
beautify: false,
// 删除全部的注释
comments: false,
}
}),
//Scope Hoisting 做用域提高,使得代码体积更小,内存开销也更小 ,
new ModuleConcatenationPlugin(),
//在 Webpack 输出最终的代码以前,对这些代码进行优化
new PrepackWebpackPlugin(),
// 生成动态连接库文件,通常会单独新建dll.config.js文件,调用此插件,把一些公共经常使用的第三方模块打包成一个动态连接库。动态连接库只须要编译一次,在以后的构建过程当中被动态连接库包含的模块将不会在从新编译,而是直接使用动态连接库中的代码。
new DllPlugin({
// 动态连接库的全局变量名称,须要和 output.library 中保持一致
// 该字段的值也就是输出的 manifest.json 文件 中 name 字段的值
// 例如 react.manifest.json 中就有 "name": "_dll_react"
name: '_dll_[name]',
// 描述动态连接库的 manifest.json 文件输出时的文件名称
path: path.join(__dirname, 'dist', '[name].manifest.json'),
}),
// 告诉 Webpack 使用了哪些动态连接库
new DllReferencePlugin({
// 描述 react 动态连接库的文件内容
manifest: require('./dist/react.manifest.json'),
}),
// 该插件的做用就是实现模块热替换,实际上当启动时带上 `--hot` 参数,会注入该插件,生成 .hot-update.json 文件。
new HotModuleReplacementPlugin(),
//自动加载模块,而没必要处处 import 或 require 。
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
]
}
复制代码
3.6 DevServer
此配置项为webpack-dev-server的专有配置项。除了在DevServer中进行配置外,还能够经过命令行参数传入。
module.exports={
...
devServer:{
hot:true,//是否启用 webpack 的模块热替换功能。DevServer 默认的行为是在发现源代码被更新后会经过自动刷新整个页面来作到实时预览,开启模块热替换功能后将在不刷新整个页面的状况下经过用新模块替换老模块来作到实时预览。
inline:true,//DevServer 的实时预览功能依赖一个注入到页面里的代理客户端去接受来自 DevServer 的命令和负责刷新网页的工做。inline 用于配置是否自动注入这个代理客户端到将运行在页面里的 Chunk 里去,默认是会自动注入。
contentBase:"",//配置 DevServer HTTP 服务器的文件根目录。 默认状况下为当前执行目录,一般是项目根目录.
//能够在 HTTP 响应中注入一些 HTTP 响应头,
headers:{
'X-foo':'bar'
},
host:127.0.0.1,//配置监听地址
port:8080,//配置监听端口号
open:true,//是否自动打开浏览器,
openPage:"index.html",//配置浏览器自启时的网页
allowedHosts: [
'host.com',
'subdomain.host.com',
'subdomain2.host.com',
'host2.com'
],//配置一个白名单列表,只有 HTTP 请求的 HOST 在列表里才正常返回
compress:true,//是否开启gzip压缩。默认为false
//展现编译信息
overlay: {
warnings: true,
errors: true
},
quiet:true,//启用 quiet 后,除了初始启动信息以外的任何内容都不会被打印到控制台。这也意味着来自 webpack 的错误或警告在控制台不可见。
//设置前端代理,访问后台
stats:"errors-only",//控制展现webpack构建信息
proxy:{
"/api": "http://localhost:3000",//表示后端服务接口地址为http://localhost:3000/api
},
//配置多个代理路径
proxy: [{
context: ["/auth", "/api"],
target: "http://localhost:3000",
}],
public:"myapp.test:80",//当启用内联模式时(inline:true),内联的客户端脚本所在的目录。
public:"/assets/",//此路径下的打包文件可在浏览器中访问.http://localhost:8080/assets/bundle.js能够范围打包后的bundle.js文件。
}
}
复制代码
3.7 其余常见配置项
module.exports={
...
devtool:"cheap-source-map", //转换过的代码(仅限行)
devtool:"cheap-source-map",//原始源代码
//开发环境的配置
devtool:"eval",//生成后的代码 ,每一个模块相互分离,并用模块名称进行注释。
devtool:"eval-source-map",//原始源代码
devtool:"cheap-eval-source-map",//转换过的代码(仅限行),它会忽略源自 loader 的 source map,而且仅显示转译后的代码
devtool:"cheap-module-eval-source-map",//原始源代码(仅限行),源自 loader 的 source map 会获得更好的处理结果
//生产环境的配置
devtool:(none),//省略该项配置 //打包后的代码,全部生成的代码视为一大块代码。你看不到相互分离的模块。
devtool:"source-map", //原始源代码,便于调试。它为 bundle 添加了一个引用注释,以便开发工具知道在哪里能够找到它。
devtool:"hidden-source-map",//与 source-map 相同,但不会为 bundle 添加引用注释。若是你只想 source map 映射那些源自错误报告的错误堆栈跟踪信息,但不想为浏览器开发工具暴露你的 source map,这个选项会颇有用。
devtool:"nosources-source-map",//建立的 source map 不包含 sourcesContent(源代码内容)。它能够用来映射客户端上的堆栈跟踪,而无须暴露全部的源代码。
target:"web",//默认值,浏览器环境
target:"node",//node环境
watch:true,//在使用 DevServer 时,监听模式默认是开启的。
//在watch配置为true时,下面的配置项才会生效。
watchOptions:{
ignored: /node_modules/,//不监听的文件夹
aggregateTimeout:300,//监听到变化发生后会等300ms再去执行动做,防止文件更新太快致使从新编译频率过高
poll:1000,//多久轮询一次
}
}
复制代码
//在index.html之外联脚本的方式引入脚本文件
<script
src="https://code.jquery.com/jquery-3.1.0.js"
integrity="sha256-slogkvB1K3VOkzAI8QITxV3VzpOnkeNVsKvtkYLMjfk="
crossorigin="anonymous">
</script>
//在配置文件中就能够经过以下配置,不讲jquery打包。
module.exports={
...
externals: {
//string类型
$: 'jQuery',
//Array类型
subtract: ['./math', 'subtract'],//表示的是。用subtract去代替./math/subtract方法。
//Object类型
lodash : {
commonjs: "lodash",
amd: "lodash",
root: "_" // 指向全局变量
}
}
}
复制代码
module.exports={
performance:{
maxEntrypointSize: 400000,//默认值是:250000 (bytes)。入口起点文件的最大致积。控制 webpack 什么时候生成性能提示.
maxAssetSize:100000,//资源(asset)是从 webpack 生成的任何文件,控制 webpack 什么时候生成性能提示。默认值是:250000 (bytes)。
hints:false | "error" | "warning",//打开或关闭提示。此属性默认设置为 "warning"。能够以提醒或错误的方式提醒你文件大小是否超过你设置的大小。
//对提示文件进行一个过滤。
assetFilter: function(assetFilename) {
return assetFilename.endsWith('.js');
}
},
stas:{
// `webpack --colors` 等同于
colors: false,
// 添加错误的详细信息(就像解析日志同样)
errorDetails: true,
// 添加时间信息
timings: true,
// 添加 webpack 版本信息
version: true,
},
//如下是默认值。从 webpack 3.0.0 开始,node 选项可能被设置为 false,以彻底关闭 NodeStuffPlugin 和 NodeSourcePlugin 插件。
node:{
console: false,// 什么都不提供。预期获取此对象的代码,可能会由于获取不到此对象,触发 ReferenceError 而崩溃
global: true,//为true时表示提供 polyfill。
process: true,
__filename: "mock",//提供 mock 实现预期接口,但功能不多或没有。
__dirname: "mock",
Buffer: true,
setImmediate: true,
}
}
复制代码
3.8 总体配置
module.exports={
context:__dirname, // Webpack 使用的根目录,入口文件所处的目录的绝对路径的字符串。
/********entry配置*******/
entry:'./app/entry', //入口模块的文件路径,能够是相对路径。
entry:['./app/entry1', './app/entry2'],//入口模块的文件路径,能够是相对路径。只有1个入口,两个入口文件
entry:{
a: './app/entry-a', b: ['./app/entry-b1', './app/entry-b2']
//配置多个入口,每一个入口生成一个 Chunk。两个入口。
},
//同步函数
entry: () => {
return {
index: "@/pages/index",
user: "@pages/user"
};
};
//异步函数
entry: () => {
return new Promise((resolve)=>{
resolve({
a:'./pages/a',
b:'./pages/b',
});
});
},
/********entry配置*******/
/********output配置*******/
output:{
//若是只有一个输出文件,则能够把它写成静态不变的。
filename:'bundle.js',
//多个 Chunk 要输出时,能够根据 Chunk 的名称来区分输出的文件名
filename: '[name].js',//能够将[name]当作字符串模板函数。该name为内置的哈希值。
filename: '[chunkhash].js', // 根据文件内容 hash 值生成文件名称,用于浏览器长时间缓存文件
chunkFilename:[name].js,//配置无入口的 Chunk 在输出时的文件名称。常见的会在运行时生成 Chunk 场景有在使用 CommonChunkPlugin、使用 import('path/to/module') 动态加载等时。
sourceMapFilename: "[file].map",//此选项会向硬盘写入一个输出文件,只在 devtool 启用了 SourceMap 选项时才使用。
path: path.resolve(__dirname, 'dist');//输出文件存放在本地的目录
publicPath:'https://cdn.example.com/assets/',//加载异步资源对应的 URL 地址。
publicPath:"/dist",//放到指定目录下
publicPath:"",//放到根目录下
//配置以何种方式导出库。注意,此选项与分配给 output.library 的值一同使用
libraryTarget:"var",//(默认值)当 library 加载完成,入口起点的返回值将分配给一个变量:
libraryTarget: "this",//入口起点的返回值将分配给 this 的一个属性(此名称由 output.library 定义)
libraryTarget: "window",//分配给 window 对象
libraryTarget: "global",//分配给 global 对象
libraryTarget: "commonjs",//入口起点的返回值将使用 output.library 中定义的值,分配给 exports 对象。
libraryTarget: "commonjs2",//入口起点的返回值将分配给 module.exports 对象
libraryTarget: "amd",//将你的 library 暴露为 AMD 模块。
libraryTarget: "umd",//将你的 library 暴露为全部的模块定义下均可运行的方式
library: "MyLibrary",
...
},
/********output配置*******/
/********module配置*******/
module:{
//让 Webpack 忽略对部分没采用模块化的文件的递归解析和处理。
noParse: /jquery|chartjs/
// 从 webpack 3.0.0 开始,也能够是函数
noParse: function(content) {
return /jquery|lodash/.test(content);
},
rules:[
{
test: /\.js$/,//转码执行后缀的文件,通常是正则表达式。可为数组
use: ['babel-loader?cacheDirectory'],//?cacheDirectory 表示传给 babel-loader 的参数,用于缓存 babel 编译结果加快从新编译速度。是loader 属性的简写方式.(如:use: [ { loader: "style-loader "} ])。
include:path.resolve(__dirname,"src"),//只命中src文件夹下的就是文件。可为数组
//解析选项对象。能够更细粒度的配置哪些模块语法要解析哪些不解析
parser:{
amd: false, // 禁用 AMD
commonjs: false, // 禁用 CommonJS
system: false, // 禁用 SystemJS
harmony: false, // 禁用 ES2015 Harmony import/export
requireInclude: false, // 禁用 require.include
requireEnsure: false, // 禁用 require.ensure
requireContext: false, // 禁用 require.context
browserify: false, // 禁用特殊处理的 browserify bundle
requireJs: false, // 禁用 requirejs.*
node: false, // 禁用 __dirname, __filename, module, require.extensions, require.main 等。
node: {...} // 在模块级别(module level)上从新配置 node 层(layer)
},
exclude:path.resolve(__dirname,'node_modules'),//排除node_module文件夹下的js文件。可为数组。
},
{
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'),
},
{
test: /\.js$/,
//use等同loaders
use:[
loader:'babel-loader',
//在 Loader 须要传入不少参数时,你还能够经过一个 Object 来描述。
options:{
cacheDirectory:true,
},
// enforce:'post' 的含义是把该 Loader 的执行顺序放到最后。 enforce 的值还能够是 pre,表明把 Loader 的执行顺序放到最前面
enforce:'post'
]
},
//loader还能够采用链式写法。loader从右到左的被调用
{
test:/\.css$/
use: [
'style-loader',
{
loader: 'css-loader',
//
options: {
importLoaders: 1
}
},
{
loader: 'less-loader',
options: {
noIeCompat: true
}
}
]
}
]
},
// 配置插件
plugins: [
//定义全局环境变量的值
new DefinePlugin({
// 定义 NODE_ENV 环境变量为 production
'process.env': {
NODE_ENV: JSON.stringify('production')
}
}),
//清除文件夹(在打包时使用)
new CleanWebpackPlugin(['dist']),
//生成模板文件,生成默认开始页面的文件,默认为index.html
new HtmlWebpackPlugin({
title: 'Output Management',
filename:"index.html",
template:"index.html",
inject:true,//将全部的资源注入到template指定的index.html中。
}),
//压缩代码(只在生产环境下使用)
new UglifyJSPlugin({
cache:true,//是否使文件缓存
parallel: true,//并行压缩代码
sourceMap:true,//是否为打包后的代码生成源码
compress: {
// 在UglifyJs删除没有用到的代码时不输出警告
warnings: false,
// 删除全部的 `console` 语句,能够兼容ie浏览器
drop_console: true,
// 内嵌定义了可是只用到一次的变量
collapse_vars: true,
// 提取出出现屡次可是没有定义成变量去引用的静态值
reduce_vars: true,
dead_code:true,//删除无用代码
},
output: {
// 最紧凑的输出
beautify: false,
// 删除全部的注释
comments: false,
}
}),
//Scope Hoisting 做用域提高,使得代码体积更小,内存开销也更小 ,
new ModuleConcatenationPlugin(),
//在 Webpack 输出最终的代码以前,对这些代码进行优化
new PrepackWebpackPlugin(),
// 生成动态连接库文件,通常会单独新建dll.config.js文件,调用此插件,把一些公共经常使用的第三方模块打包成一个动态连接库。动态连接库只须要编译一次,在以后的构建过程当中被动态连接库包含的模块将不会在从新编译,而是直接使用动态连接库中的代码。
new DllPlugin({
// 动态连接库的全局变量名称,须要和 output.library 中保持一致
// 该字段的值也就是输出的 manifest.json 文件 中 name 字段的值
// 例如 react.manifest.json 中就有 "name": "_dll_react"
name: '_dll_[name]',
// 描述动态连接库的 manifest.json 文件输出时的文件名称
path: path.join(__dirname, 'dist', '[name].manifest.json'),
}),
// 告诉 Webpack 使用了哪些动态连接库
new DllReferencePlugin({
// 描述 react 动态连接库的文件内容
manifest: require('./dist/react.manifest.json'),
}),
// 该插件的做用就是实现模块热替换,实际上当启动时带上 `--hot` 参数,会注入该插件,生成 .hot-update.json 文件。
new HotModuleReplacementPlugin(),
//自动加载模块,而没必要处处 import 或 require 。
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
],
// 配置寻找模块的规则
resolve:{
//经过别名来把原导入路径映射成一个新的导入路径
alias:{
'components': './src/components/',
'@':"./src",
~:"./src",
'vue$': 'vue/dist/vue.esm.js',
}
//指定一个字段,例如 browser(浏览器环境),根据此规范进行解析。只会使用找到的第一个
aliasFields:['browser', 'main']
descriptionFiles:["package.json"],//描述文件
enforceExtension:false,//是否强制扩展名
extensions:[".js",".json"],//自动解析的扩展,导入语句没带文件后缀时,Webpack 会自动带上后缀后去尝试访问文件是否存在.
modules:['./src/components','node_modules'],//告诉 webpack 解析模块时应该搜索的目录。绝对路径和相对路径都能使用。
},
//开发模式下的服务器配置
devServer:{
hot:true,//是否启用 webpack 的模块热替换功能。DevServer 默认的行为是在发现源代码被更新后会经过自动刷新整个页面来作到实时预览,开启模块热替换功能后将在不刷新整个页面的状况下经过用新模块替换老模块来作到实时预览。
inline:true,//DevServer 的实时预览功能依赖一个注入到页面里的代理客户端去接受来自 DevServer 的命令和负责刷新网页的工做。inline 用于配置是否自动注入这个代理客户端到将运行在页面里的 Chunk 里去,默认是会自动注入。
contentBase:"",//配置 DevServer HTTP 服务器的文件根目录。 默认状况下为当前执行目录,一般是项目根目录.
//能够在 HTTP 响应中注入一些 HTTP 响应头,
headers:{
'X-foo':'bar'
},
host:127.0.0.1,//配置监听地址
port:8080,//配置监听端口号
open:true,//是否自动打开浏览器,
openPage:"index.html",//配置浏览器自启时的网页
allowedHosts: [
'host.com',
'subdomain.host.com',
'subdomain2.host.com',
'host2.com'
],//配置一个白名单列表,只有 HTTP 请求的 HOST 在列表里才正常返回
compress:true,//是否开启gzip压缩。默认为false
//展现编译信息
overlay: {
warnings: true,
errors: true
},
quiet:true,//启用 quiet 后,除了初始启动信息以外的任何内容都不会被打印到控制台。这也意味着来自 webpack 的错误或警告在控制台不可见。
//设置前端代理,访问后台
stats:"errors-only",//控制展现webpack构建信息
proxy:{
"/api": "http://localhost:3000",//表示后端服务接口地址为http://localhost:3000/api
},
//配置多个代理路径
proxy: [{
context: ["/auth", "/api"],
target: "http://localhost:3000",
}],
public:"myapp.test:80",//当启用内联模式时(inline:true),内联的客户端脚本所在的目录。
public:"/assets/",//此路径下的打包文件可在浏览器中访问.http://localhost:8080/assets/bundle.js能够范围打包后的bundle.js文件。
},
//source map配置
devtool:"cheap-source-map", //转换过的代码(仅限行)
devtool:"cheap-source-map",//原始源代码
//开发环境的配置
devtool:"eval",//生成后的代码 ,每一个模块相互分离,并用模块名称进行注释。
devtool:"eval-source-map",//原始源代码
devtool:"cheap-eval-source-map",//转换过的代码(仅限行),它会忽略源自 loader 的 source map,而且仅显示转译后的代码
devtool:"cheap-module-eval-source-map",//原始源代码(仅限行),源自 loader 的 source map 会获得更好的处理结果
//生产环境的配置
devtool:(none),//省略该项配置 //打包后的代码,全部生成的代码视为一大块代码。你看不到相互分离的模块。
devtool:"source-map", //原始源代码,便于调试。它为 bundle 添加了一个引用注释,以便开发工具知道在哪里能够找到它。
devtool:"hidden-source-map",//与 source-map 相同,但不会为 bundle 添加引用注释。若是你只想 source map 映射那些源自错误报告的错误堆栈跟踪信息,但不想为浏览器开发工具暴露你的 source map,这个选项会颇有用。
devtool:"nosources-source-map",//建立的 source map 不包含 sourcesContent(源代码内容)。它能够用来映射客户端上的堆栈跟踪,而无须暴露全部的源代码。
externals: { // 使用来自 JavaScript 运行环境提供的全局变量
//string类型
$: 'jQuery',
//Array类型
subtract: ['./math', 'subtract'],//表示的是。用subtract去代替./math/subtract方法。
//Object类型
lodash : {
commonjs: "lodash",
amd: "lodash",
root: "_" // 指向全局变量
}
},
// 配置输出代码的运行环境
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, 渲染线程
//开启监听模式
watch:true,//在使用 DevServer 时,监听模式默认是开启的。
//在watch配置为true时,下面的配置项才会生效。
watchOptions:{
ignored: /node_modules/,//不监听的文件夹
aggregateTimeout:300,//监听到变化发生后会等300ms再去执行动做,防止文件更新太快致使从新编译频率过高
poll:1000,//多久轮询一次
}
stats: { // 控制台输出日志控制,webpack构建时的统计信息。
assets: true,//添加资源信息
colors: true,// `webpack --colors` 等同于
errors: true,//输出错误信息
errorDetails: true,//// 添加错误的详细信息(就像解析日志同样)
hash: true,//添加 compilation 的哈希值
version:true,//添加尾巴爬虫库版本信息
performance: true,// 当文件大小超过 `performance.maxAssetSize` 时显示性能提示
modules: true,// 添加构建模块信息,
// 添加时间信息
timings: true,
},
// 输出文件性能检查配置,这些选项能够控制 webpack 如何通知「资源(asset)和入口起点超过指定文件限制」。
performance:{
maxEntrypointSize: 400000,//默认值是:250000 (bytes)。入口起点文件的最大致积。控制 webpack 什么时候生成性能提示.
maxAssetSize:100000,//资源(asset)是从 webpack 生成的任何文件,控制 webpack 什么时候生成性能提示。默认值是:250000 (bytes)。
hints:false | "error" | "warning",//打开或关闭提示。此属性默认设置为 "warning"。能够以提醒或错误的方式提醒你文件大小是否超过你设置的大小。
//对提示文件进行一个过滤。
assetFilter: function(assetFilename) {
return assetFilename.endsWith('.js');
}
},
//配置是否 polyfill 或 mock 某些 Node.js 全局变量和模块。这可使最初为 Node.js 环境编写的代码,在其余环境(如浏览器)中运行。此功能由 webpack 内部的 NodeStuffPlugin 插件提供。
node:{
console: false,// 什么都不提供。预期获取此对象的代码,可能会由于获取不到此对象,触发 ReferenceError 而崩溃
global: true,//为true时表示提供 polyfill。
process: true,
__filename: "mock",//提供 mock 实现预期接口,但功能不多或没有。
__dirname: "mock",
Buffer: true,
setImmediate: true,
}
}
复制代码
3.9 多种配置类型
配置文件除了以Object的形式输出之外,还能够以function或者promise的形式输出,同时还能够导出多个配置对象。
//以对象的形式,须要写多个配置文件以适应"开发和生产"模式
module.exports={
entry:"app.js",
output:{
},
...
},
//导出多个配置对象
module.exports=[{
output: {
filename: './dist-amd.js',
libraryTarget: 'amd'
},
entry: './app.js',
mode: 'production',
}, {
output: {
filename: './dist-commonjs.js',
libraryTarget: 'commonjs'
},
entry: './app.js',
mode: 'production',
}]
//以function的形式,采用导出一个 Function 的方式,能经过 JavaScript 灵活的控制配置,作到只用写一个配置文件就能完成以上要求。
module.exports=function(env={},args){
const isProduction=env["production"];
const plugins=[];
//返回的仍是那些配置文件
return {
plugins: plugins,
// 在生成环境不输出 Source Map
devtool: isProduction ? undefined : 'source-map',
};
}
//以promise的形式导出
module.exports=function(env={},args){
return new Promise(resolve,reject){
setTimeout(() => {
resolve({
entry: './app.js',
/* ... */
})
}, 5000)
}
}
复制代码
以函数的形式导出配置文件时。
4.1 开发环境下的优化
1)、缩小文件搜索范围(主要是对配置项中的module和resolve配置项进行优化)
module.exports={
//一、优化module配置项中的查找范围
module:{
//一、忽略对部分没采用模块化的文件的递归解析处理,这样作的好处是能提升构建性能。
noParse:/jQuery|ChartJS/,
rules:[
test: /\.js$/,
use:["babel-loader"]
include:path.resolve(__dirname, 'src'),//二、缩小搜索范围
]
},
//二、缩小resolve模块搜索范围
resolve: {
// 一、使用绝对路径指明第三方模块存放的位置,以减小搜索步骤
// 其中 __dirname 表示当前工做目录,也就是项目根目录
modules: [path.resolve(__dirname, 'node_modules')],
//二、在明确第三方模块的入口文件描述字段时。能够只采用 main(单个字段) 字段做为入口文件描述字段,以减小搜索步骤。
mainFields: ['main'],
alias:{
"@":"./src",//三、经过配置别名来跳过耗时的递归解析操做。
}
//四、这个列表越长,或者正确的后缀在越后面,就会形成尝试的次数越多
extensions: ['.js', '.json']
},
}
复制代码
2)、使用动态连接库(DllPlugin)
//新建一个dll.config.js文件,跟日常的配置文件同样
const DllPlugin = require('webpack/lib/DllPlugin');
module.export={
entry:{
vender:["vue","axios","vue-router","vuex"]
},
output:{
path:resolve(__dirname,"../src/static"),
filename:"[name].js",
library:"[name]_library"
}
plugins: [
// 接入 DllPlugin
new DllPlugin({
// 动态连接库的全局变量名称,须要和 output.library 中保持一致
// 该字段的值也就是输出的 manifest.json 文件 中 name 字段的值
// 例如 react.manifest.json 中就有 "name": "_dll_react"
name: '_dll_[name]',
// 描述动态连接库的 manifest.json 文件输出时的文件名称
path: path.join(__dirname, 'dist', '[name].manifest.json'),
}),
],
}
//在开发或生产环境配置文件中
const DllReferencePlugin = require('webpack/lib/DllReferencePlugin');
module.exports={
...
plugins:[
new DllReferencePlugin({
// 描述 react 动态连接库的文件内容
manifest: require('./dist/vender.manifest.json'),
}),
]
}
复制代码
3)、使用HappyPack(并行loader去转换代码)
//它把任务分解给多个子进程去并发的执行,子进程处理完后再把结果发送给主进程。
const HappyPack = require('happypack');
module.exports={
module:{
rules:[
{
test: /\.js$/,
// 把对 .js 文件的处理转交给 id 为 babel 的 HappyPack 实例
use: ['happypack/loader?id=babel'],
// 排除 node_modules 目录下的文件,node_modules 目录下的文件都是采用的 ES5 语法,不必再经过 Babel 去转换
exclude: /node_modules/,
},{
// 把对 .css 文件的处理转交给 id 为 css 的 HappyPack 实例
test: /\.css$/,
use: ['happypack/loader?id=css'],
}
]
},
plugins:[
new HappyPack({
// 用惟一的标识符 id 来表明当前的 HappyPack 是用来处理一类特定的文件
id: 'babel',
// 如何处理 .js 文件,用法和 Loader 配置中同样
loaders: ['babel-loader?cacheDirectory'],
// ... 其它配置项
}),
new HappyPack({
// 用惟一的标识符 id 来表明当前的 HappyPack 是用来处理一类特定的文件
id: 'css',
// 如何处理 .js 文件,用法和 Loader 配置中同样
loaders: ['css-loader'],
// ... 其它配置项
}),
]
}
复制代码
1)、使用自动刷新
文件监听:在发现源码文件发生变化时,自动从新构建出新的输出文件。是 webpack 模块提供的。
文件监听原理:Webpack 中监听一个文件发生变化的原理是定时的去获取这个文件的最后编辑时间,每次都存下最新的最后编辑时间,若是发现当前获取的和最后一次保存的最后编辑时间不一致,就认为该文件发生了变化。
自动刷新的原理:webpack 模块负责监听文件,webpack-dev-server 模块则负责刷新浏览器。 在使用 webpack-dev-server 模块去启动 webpack 模块时,webpack 模块的监听模式默认会被开启。
控制浏览器刷新有三种方法:
1、借助浏览器扩展去经过浏览器提供的接口刷新,WebStorm IDE 的 LiveEdit 功能就是这样实现的。
2、往要开发的网页中注入代理客户端代码,经过代理客户端去刷新整个页面。(DevServer默认采用的,为输出的每一个chunk注入代理客户端,是经过inline属性来控制的。)
3、把要开发的网页装进一个 iframe 中,经过刷新 iframe 去看到最新效果。
module.exports = {
// 只有在开启监听模式时,watchOptions 才有意义
// 默认为 false,也就是不开启
watch: true,
// 监听模式运行时的参数
// 在开启监听模式时,才有意义
watchOptions: {
// 不监听的文件或文件夹,支持正则匹配
// 默认为空
ignored: /node_modules/,
// 监听到变化发生后会等300ms再去执行动做,防止文件更新太快致使从新编译频率过高
// 默认为 300ms
//值越大性能越好,由于这能下降从新构建的频率。
aggregateTimeout: 300,
// 判断文件是否发生变化是经过不停的去询问系统指定文件有没有变化实现的
// 默认每隔1000毫秒询问一次
//值越大越好,由于这能下降检查的频率。
poll: 1000,
}
}
复制代码
2)、开启模块热加载
模块热加载原理:当一个源码发生变化时,只从新编译发生变化的模块,再用新输出的模块替换掉浏览器中对应的老模块。
优势:
1、实时预览反应更快,等待时间更短。
2、不刷新浏览器,并且能保留当前网页的运行状态。
module.exports={
devServer:{
hot:true,
}
}
当子模块发生更新时,更新事件会一层层往上传递,直到有某层的文件接受了当前变化的模块,若是事件一直往上抛到最外层都没有文件接受它,就会直接刷新网页。
优化模块热更新:在main.js中注入以下代码。
if (module.hot) {
module.hot.accept(['./AppComponent'], callback);
//'./AppComponent':表示监听的模块;callback表示回调。
}
module.exports = {
plugins: [
// 显示出被替换模块的名称
new NamedModulesPlugin(),
],
};
注意:
1、关闭默认的 inline 模式手动注入代理客户端的优化方法不能用于在使用模块热替换的状况下。
2、监听更少的文件,忽略掉 node_modules 目录下的文件。
复制代码
4.2 生产环境下的优化
1)、区分环境
2)、压缩代码
1、这里压缩的是ES6代码。
const UglifyESPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
plugins: [
new UglifyESPlugin({
// 多嵌套了一层,用于压缩ES6代码
uglifyOptions: {
compress: {
// 在UglifyJs删除没有用到的代码时不输出警告
warnings: false,
// 删除全部的 `console` 语句,能够兼容ie浏览器
drop_console: true,
// 内嵌定义了可是只用到一次的变量
collapse_vars: true,
// 提取出出现屡次可是没有定义成变量去引用的静态值
reduce_vars: true,
},
output: {
// 最紧凑的输出
beautify: false,
// 删除全部的注释
comments: false,
}
}
})
]
}
2、压缩css代码
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
module: {
rules: [
{
test: /\.css$/,// 增长对 CSS 文件的支持
// 提取出 Chunk 中的 CSS 代码到单独的文件中
use: ExtractTextPlugin.extract({
// 经过 minimize 选项压缩 CSS 代码
use: ['css-loader?minimize']
}),
},
]
},
plugins: [
new ExtractTextPlugin({
filename: `[name]_[contenthash:8].css`,// 给输出的 CSS 文件名称加上 Hash 值
}),
],
};
复制代码
3)、使用CDN进行加速
CDN 又叫内容分发网络,经过把资源部署到世界各地,用户在访问时按照就近原则从离用户最近的服务器获取资源,从而加速资源的获取速度。
使用CDN要注意的问题:
1、针对 HTML 文件:不开启缓存,把 HTML 放到本身的服务器上,而不是 CDN 服务上,同时关闭本身服务器上的缓存。
2、针对静态的 JavaScript、CSS、图片等文件:开启 CDN 和缓存,上传到 CDN 服务上去,同时给每一个文件名带上由文件内容算出的 Hash 值。带上 Hash 值的缘由是文件名会随着文件内容而变化,只要文件发生变化其对应的 URL 就会变化,它就会被从新下载,不管缓存时间有多长。
Webpack 实现 CDN 的接入要注意一下几点:
1、静态资源的导入 URL 须要变成指向 CDN 服务的绝对路径的 URL 而不是相对于 HTML 文件的 URL。
2、静态资源的文件名称须要带上有文件内容算出来的 Hash 值,以防止被缓存。
3、不一样类型的资源放到不一样域名的 CDN 服务上去,以防止资源的并行加载被阻塞。
在webpack中的基本配置以下:
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const htmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
// 省略 entry 配置...
output: {
// 给输出的 JavaScript 文件名称加上 Hash 值
filename: '[name]_[chunkhash:8].js',
path: path.resolve(__dirname, './dist'),
// 指定存放 JavaScript 文件的 CDN 目录 URL
publicPath: '//js.cdn.com/id/',
},
module: {
rules: [
{
// 增长对 CSS 文件的支持
test: /\.css$/,
// 提取出 Chunk 中的 CSS 代码到单独的文件中
use: ExtractTextPlugin.extract({
// 压缩 CSS 代码
use: ['css-loader?minimize'],
// 指定存放 CSS 中导入的资源(例如图片)的 CDN 目录 URL
publicPath: '//img.cdn.com/id/'
}),
},
]
},
plugins: [
// 使用 WebPlugin 自动生成 HTML
new htmlWebpackPlugin({
// HTML 模版文件所在的文件路径
template: './template.html',
// 输出的 HTML 的文件名称
filename: 'index.html',
// 指定存放 CSS 文件的 CDN 目录 URL
stylePublicPath: '//css.cdn.com/id/',
}),
new ExtractTextPlugin({
// 给输出的 CSS 文件名称加上 Hash 值
filename: `[name]_[contenthash:8].css`,
}),
// 省略代码压缩插件配置...
],
};
复制代码
4)、使用Tree-Shaking删除无用的代码
Tree Shaking 能够用来剔除 JavaScript 中用不上的死代码。它依赖静态的 ES6 模块化语法。
Tree Shaking的局限性在于:
1、不会对entry入口文件作 Tree Shaking。
2、不会对异步分割出去的代码作 Tree Shaking。
想要是Tree Shaking起做用,须要作到这几步。
1、修改.babelrc 文件
{
"presets": [
[
"env",
{
"modules": false
}
]
]
}
2、使用代码压缩(在命令行中加上--optimize-minimize)
module.exports={
resolve: {
// 针对 Npm 中的第三方模块优先采用 jsnext:main 中指向的 ES6 模块化语法的文件(Tree Shaking只对ES6模块化语法的文件起做用,因此须要以下配置。)
mainFields: ['jsnext:main', 'browser', 'main']
},
plugins:[
new UglifyJSPlugin()
]
}
复制代码
5)、进行按需加载(使用import())
6)、提取公共代码
module.exports={
...
optimization:{
splitChunks: {
cacheGroups:{ // 这里开始设置缓存的
vendor: { // key 为entry中定义的 入口名称
priority: 1, // 缓存组优先级
chunks: "all",
test: /[\\/]node_modules[\\/]babel-runtime/,
name: 'babel-runtime',
}
}
},
}
}
复制代码
1)、开启 Scope Hoisting(较少函数声明语句)
Scope Hoisting 可让 Webpack 打包出来的代码文件更小、运行的更快, 它又译做 "做用域提高"。Scope Hoisting 的实现原理其实很简单:分析出模块之间的依赖关系,尽量的把打散的模块合并到一个函数中去,但前提是不能形成代码冗余。 所以只有那些被引用了一次的模块才能被合并。所以源码必须采用 ES6 模块化语句,否则它将没法生效。
使用Scope Hoisting的好处:
1、代码体积更小,由于函数声明语句会产生大量代码;
2、代码在运行时由于建立的函数做用域更少了,内存开销也随之变小。
const ModuleConcatenationPlugin = require('webpack/lib/optimize/ModuleConcatenationPlugin');
module.exports = {
resolve: {
// 针对 Npm 中的第三方模块优先采用 jsnext:main 中指向的 ES6 模块化语法的文件
mainFields: ['jsnext:main', 'browser', 'main']
},
plugins: [
// 开启 Scope Hoisting
new ModuleConcatenationPlugin(),
],
};
复制代码
后记:至于webpack的原理及loader和plugin的原理及编写这里就不在啰嗦了。这样的资料网上一搜一大把。这片文档主要是对webpack的配置及优化作了一些总结。资料来源主要是《升入浅出webpack》和webpack的官网。