近期一直在看webpack4的文档,因而给本身作了这个总结,对比一下生产环境和开发环境的区别。javascript
在项目开发过程当中,咱们关注的是可否追溯到代码的错误来源,可以及时刷新页面让咱们看到代码的实际效果,所以webpack针对开发特色提供了几个插件。css
webpack会将代码打包至一个文件中,一旦发生错误和警告,很难追溯到其来源,所以webpack提供了source-map,将编译后的代码映射回原始代码。java
官网示例代码结果如图:node
source-map有多种使用方式,官方推荐三种使用方式:devtool, SourceMapDevToolPlugin或EvalSourceMapDevToolPlugin。第一种采用的是内置插件,第2、第三种是直接插入插件。三种方式不能同时出现,不然会致使插件被置入两次。webpack
devtoolweb
devtool: 'inline-source-map',
复制代码
webpack官网中列举出来了一些devtool属性的性能对比(地址),咱们能够根据本身项目的须要来选用。npm
插件能够对source-map生成更细粒度的控制,能够做为插件使用,也能够在经过devtool的某些设置来自动开启json
SourceMapDevToolPlugin后端
new webpack.SourceMapDevToolPlugin(options);
复制代码
在使用TerserPlugin时,您必须使用该sourceMap选项。api
EvalSourceMapDevToolPlugin
new webpack.EvalSourceMapDevToolPlugin(options);
复制代码
每次编写完代码后都须要运行npm run build很是麻烦,所以webpack提供了三种不一样的开发工具支持实时更新代码。
经过添加npm脚本的方式来监控代码的变化,在package.json中添加一行
"scripts": {
"watch": "webpack --watch"
}
复制代码
此时启动npm run watch即可以监控代码,咱们能够查看到文件的hash值一直在变化,表示文件一直在跟随代码的更新而变化。
该方法提供一个简单的web服务器和使用实时从新加载的能力。所以是使用较多的一个工具。webpack-dev-server从devServer中读取配置,
devServer: {
contentBase: './dist'
}
复制代码
contentBase告诉webpack-dev-server从dist目录中提供文件,显示在localhost:8080上。
webpack-dev-server并不会输出编译后的文件,而是将文件保存在内存中提供服务,开启本地服务器来监控代码并实时刷新网页。
webpack-dev-server开启的是本地服务器,而一般咱们在开发过程当中须要与后端进行通讯,调试数据。本地服务器会有跨域问题,所以咱们能够经过devServer设置代理来请求接口
devServer: {
proxy: {
'/api': 'http://localhost:3000'
}
}
复制代码
固然咱们也能够经过一些代理软件来对处理本地请求的问题,只是webpack-dev-server本身也实现了这个功能。
更多具体的配置能够查阅官网文档
webpack-dev-middleware是一个包装器,将webpack处理后的文件发送到服务器,在webpack-dev-server内部也是经过这个中间件来实现的,也能够做为单独的包提供,容许更多自定义设置。
webpack-dev-middleware在使用时须要配置output的publicPath属性,以确保正确提供文件。添加文件server.js, 在该文件中设置相应的自定义,即可以启动中间件运行。下面是官网的自定义示例:
生产环境与开发环境彻底不一样,在生产环境中咱们关注的是如何才能产生更小的代码块,压缩文件的体积,使得加载时间作到最短。
webpack鼓励开发人员在生产环境中也加入source-map,便于调试和运行基准测试。在生产环境中应当选择构建速度较快的source-map,尽可能避免在生产环境中使用inline-*** 或 eval-*** 的source-map,由于它们会显著增长包的体积并下降总体性能。
推荐配置:devtool: 'source-map'
优化css代码是生产构建中很是重要的一环,webpack4+为此专门提供了一个css插件:MiniCssExtractPlugin,为每一个包含CSS的JS文件建立一个CSS文件。它支持CSS和SourceMaps的按需加载。 与以前使用的extract-text-webpack-plugin插件(webpack4+已废弃)相比,webpack4提供的这个插件具备更加显著的优势:异步加载、没有重复编译、性能更加良好、更容易使用、定制css。并且官网指明在将来这个插件有可能会支持热重载。
须要注意的是,MiniCssExtractPlugin只应该在生产环境中被使用,并且在生产环境中应该使用它来替代style-loader。同时配合插件optimize-css-assets-webpack-plugin来压缩css文件。
module.exports = {
optimization: {
minimizer: [
new TerserJSPlugin({}), // 须要显式的指定js minimalizer,由于optimization.minimizer会覆盖默认设置
new OptimizeCSSAssetsPlugin({})
]
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
chunkFilename: "[id].css"
})
],
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader"
]
}
]
}
}
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
"css-loader"
]
}
]
}
复制代码
tree shaking是Javascript上下文中去除死代码的一个术语,它依赖于ES5的模块语法的静态结构,即import和export语法。在webpack2中已内置支持ES2015的模块语法,在webpack4中队这一功能进行了扩充,经过package.json中的'sideEffects'来标识项目中哪些文件是纯粹的,若是未使用则能够安全修建。 可是在使用tree shaking时须要注意,只有无反作用的代码才能够应用修剪,
“反作用”定义为在导入时执行特殊行为的代码,而不是公开一个或多个导出。一个例子是polyfill,它影响全局范围,一般不提供导出。 |
在webpack4以上的环境中,在package.json中添加'sideEffects'属性,并将mode设置为production便可开启tree shaking。固然,tree shaking只是标识出能够被修剪掉的代码块,最后仍是须要使用UglifyjsWebpackPlugin插件来进行js压缩。
注意:tree shaking只支持ES6模块语法,不能识别CommonJS语法,由于CommonJS是动态导入,没法被识别
在使用webpack的时候,咱们都会学到一个概念,webpack会将全部代码都打包到一个文件中去,形成该文件的体积十分的庞大,所以webpack提供了代码拆分功能,咱们能够将一些代码提取成不一样的bundles,实现按需加载或并行加载。使用得当的话能很大的提高加载效率。一般有三种代码拆方式:
webpack4.6.0+版本增长了对预加载和预获取的支持:
在webpack4+中,推荐使用SplitChunksPlugin来分离代码,这个插件容许咱们将共同的依赖提取到一个现有的块或者一个全新的块中去。相较于以前使用的CommonsChunkPlugin插件(webpack4+已废弃),webpack在SplitChunksPlugin中作了更多的优化,在基于如下的条件时新的代码块会被自动建立:
同时SplitChunksPlugin提供了丰富的api供咱们实现个性化设置,咱们能够根据本身的项目特性来设置如何分离代码块。详情查询
SplitChunksPlugin配置以下:
module.exports = {
//...
optimization: {
splitChunks: {
chunks: 'async',
minSize: 30000,
maxSize: 0,
minChunks: 1,
maxAsyncRequests: 5,
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true
}
}
}
}
};
复制代码
该插件支持咱们配置缓存组来缓存不一样的文件,经过test配置来选择什么样的模块能够进入该缓存组。
// 该名为vendors的缓存组能够缓存全部来自node_modules的文件
splitChunks: {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: "vendors",
chunks: "all"
}
}
}
// 注意:这可能会致使下载额外的代码。
// 实际应用中应该只包含核心功能和框架,避免包过于庞大。
复制代码
webpack4中对于区分开发和生产环境的不一样提出了两种解决方案:webpack-merge和env环境变量。
安装了webpack-merge之后,咱们须要修改本来的webpack.config.js
- webpack.config.js
+ webpack.common.js
+ webpack.dev.js
+ webpack.prod.js
复制代码
webpack.common.js是设置entry, output等通用设置和开发环境、生产环境都能使用的插件的配置文件。 webpack.dev.js须要设置mode为development,表示这是开发环境,一样咱们的devtool(使用强效source-map),devServer也是配置在这个文件,咱们能够在这个文件中作一些针对本身项目开发需求的个性化配置。 webpack.prod.js设置mode为production,表示生产环境,此时webpack4默认启用插件TerserPlugin,咱们能够将压缩文件的插件、针对生产环境的一些优化措施放置在里面。
webpack的环境变量跟操做系统的环境变量是不一样的,webpack容许咱们传入任意数量的环境变量,经过命令行--env传入。可是若要使用该环境变量,须要将module.exports变为函数,将环境变量以参数的形式传入。
// webpack.config.js
const path = require('path');
module.exports = env => {
// 使用你的环境变量
console.log('NODE_ENV: ', env.NODE_ENV);
console.log('Production: ', env.production);
return {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
};
复制代码
经过这样,咱们即可以区分出不一样的环境须要的不一样的配置。
webpack容许运行在node.js中,因为它是单线程模型,所以不能并行处理多个任务,Happy Pack将任务分解给多个子进程去并发执行,子进程处理完成后再将结果发送给主进程,所以能实现让webpack同时处理多个任务,减小构建时间。
const HappyPack = require('happypack');
module.exports = {
module: {
rules: [
{
test: /\.js$/,
// 将对.js文件的处理转交给id为babel的HappyPack的实列
use: ['happypack/loader?id=babel'],
exclude: path.resolve(__dirname, 'node_modules') // 排除文件
}
]
},
plugins: [
/**** 使用HappyPack实例化 *****/
new HappyPack({
// 用惟一的标识符id来表明当前的HappyPack 处理一类特定的文件
id: 'babel',
// 处理文件,用法和Loader配置是同样的
loaders: ['babel-loader']
})
]
}
复制代码
在loader中,将对文件的处理都传递给happypack/loader,利用id做为标识符。而后在plugin插件中新增HappyPack实例,告诉HappyPack须要作的事情。 HappyPack是为了解决webpack在node中单线程执行构建速度慢而存在的一个插件,可以显著的提升webpack的构建速度。
在开发环境中,咱们更注重的是如何及时快速的将更新的代码展现在网页上,如何快速定位错误,所以webpack提供了强效source-map和模块热更新的机制来帮助开发人员。在生产环境中,咱们须要的是如何让代码包更小、构建更迅速,所以有了轻量级source-map,css代码压缩工具,tree shaking配和js压缩工具等等,都是为了让最后打包出来的代码体量更小。 一样在项目较为复杂的时候也须要将代码进行分包处理,使用异步加载,进一步提升用户使用时的加载速度,一样为了弥补webpack在node中也是单线程加载的缘由,还提供了HappyPack,使得webpack可以并行加载。