为了使用tree shaking,需要满足以下条件:
这种方式是通过package.json的sideEffects属性来实现的。
{
"sodeEffects": false
}
「副作用」的定义是,在导入时会执行特殊行为的代码,而不是仅仅暴露一个export或多个export。举例说明,例如polyfill,它影响全局作用域,并且通常不提供export。
注意,任何导入的文件都会受到tree shaking的影响。这意味着,如果在项目中使用类似css-loader并导入CSS文件,则需要将其添加到 side effect 列表中,以免在生产模式中无意中将它删除:
{
"sideEffects": ['*.css']
}
从 webpack 4 开始,也可以通过 "mode" 配置选项轻松切换到压缩输出,只需设置为 "production"。
也可以在命令行接口中使用--optimize-minimize标记,来使用UglifyJSPlugin。
code splitting的必要性
import _ from 'lodash';
webpack.common.js配置如下:
....
optimization: {
splitChunks: {
chunks: 'all'
}
}
....
配置后,会将公用类库进行打包,生成一个vendors~main.js文件。
function getComponent() {
return import('lodash').then(({ default: _ }) => {
var element = document.createElement('div');
element.innerhtml = _.join(['Clear', 'love'], '');
return element;
})
}
getComponent().then(element => {
document.body.appendChild(element);
})
在.babelrc中引用该插件
....
plugins: ['@babel/plugin-syntax-dynamic-import']
....
function getComponent() {
return import(/* webpackChunkName:"lodash" */'lodash').then(({ default: _ }) => {
var element = document.createElement('div');
element.innerHTML = _.join(['Clear', 'love'], '');
return element;
})
}
getComponent().then(element => {
document.body.appendChild(element);
})
关键是注释:webpackChunkName: "lodash".。打包后的文件名为vendors~lodash.js。
若想打包过后的文件名不带vendors~前缀,可以修改webpack.common.js中optimization配置项:
....
optimization: {
splitChunks: {
chunks: "all",
cacheGroups: {
venders: false,
default: false
}
}
}
....
splitChunks: {
chunks: 'async', // all async initial 是否对异步代码进行的代码分割
minSize: 30000, // 引入模块大于30kb才进行代码分割
maxSize: 0, // 引入模块大于Xkb时,尝试对引入模块二次拆分引入
minChunks: 1, // 引入模块至被使用X次后才进行代码分割
maxAsyncRequests: 5, //
maxInitialRequests: 3,
automaticNameDelimiter: '~',
name: true,
cacheGroups: {
vendors: {
test: /[\\/]node_modules[\\/]/,
priority: -10, // 优先级
filename: 'vendors.js' // 打包文件名称
},
default: {
minChunks: 2,
priority: -20,
reuseExistingChunk: true // 是否复用已打包代码
}
}
}
}
function getComponent() {
return import(/* webpackChunkName:"lodash" */'lodash').then(({ default: _ }) => {
var element = document.createElement('div');
element.innerHTML = _.join(['Clear', 'love'], '');
return element;
})
}
document.addEventListener('click', () => {
/* 当点击时才加载lodash */
getComponent().then(element => {
document.body.addChild(element);
})
})
页面初始化时,不会加载lodash。当点击页面时才加载。
import引入动态组件实现的Lazy Loading,其实跟Webpack没什么关系。import是ES6的语法标准。而Webpack借助babel-profill能识别该语法。
每个打包的js文件都是一个chunk
在package.json的scripts项中进行配置:
....
scripts: {
"dev-build": "webpack --profile --json > stats.json --config ./build/webpack.dev.js"
}
....
打包后会生成stats.json,然后上传该文件至webpack/analyse进行分析
document.addEventListener('click', () => {
import(/* webpackPrefetch: true */ 'lodash').then(() => {
....
})
})
Preload和Prefetch的区别:
具体可以参考prefetching/preloading-modules
若没有进行css的代码分割,通过import方式引入的样式文件,将会被当作普通的模块打包到.js文件中。
若需要对css进行代码分割,需要借助optimize-css-assets-webpack-plugin插件实现,具体如下:
// webpack.prod.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
....
module: [{
test: /\.scss$/,
use: [
MiniCssExtractPlugin.loader,
{
loder: 'css-loader',
options: { importLoaders: 2 }
},
'saas-loader',
'postcss-loaerd'
]
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
}],
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css', // 入口文件中直接引入css匹配该规则
chunkFilename: '[name].chunk.css' // 非入口文件中引入或嵌套引入匹配匹配该规则
})
]
....
若需要对引入css进行合并、压缩,可以借助optimize-css-assets-webpack-plugin。,具体配置如下:
// webpack.prod.js
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin")
....
optimization: {
minimizer: [new OptimizeCSSAssetsPlugin({})]
}
....
若之前有配置过tree shaking,则需要对以下文件进行修改:
optimization: {
usedExports: true
}
"sideEffects": [
"*.css"
]
webpack实现浏览器缓存,主要是借助配置output中的contenthash来实现的。
// webpack.prod.js
....
output: {
filename: '[name].[contenthash].js',
chunkFilename: '[name].[contenthash].js'
}
....
旧版webpack进行打包时,虽然文件没有进行任何修改,但打包后生成的contenthash还是会改变,这时需要再进行一些配置。
// webpack.common.js
....
optimization: {
runtimeChunk: {
name: 'runtime'
}
}
....
使用最新稳定版本的webpack、node、npm等,较新的版本更够建立更高效的模块树以及提高解析速度。
将loaders应用于最少数的必要模块中,而不是:
// webpack.common.js
module: {
rules: [
{
test: /\.jsx?$/,
use: ['babel-loader']
}
]
}
使用include字段仅将loader模块应用在实际需要用其转换的位置:
// webpack.common.js
module: {
rules: [
{
test: /\.jsx?$/,
include: path.resolve(__dirname, '../src'),
use: ['babel-loader']
}
]
}
减少编译的整体大小,以提高构建性能。尽量保持chunks小巧。
thread-loader可以将非常耗性能的loaders转存到worker pool中。<br/>
不要使用太多的 workers ,因为 Node.js 的 runtime 和 loader 有一定的启动开销。最小化 workers 和主进程间的模块传输。进程间通讯(IPC)是非常消耗资源的。
对于一些性能开销较大的loader之前可以添加cache-loader,启用持久化缓存。
使用package.json中的postinstall清楚缓存目录。
使用DllPlugin将更新不频繁的代码进行单独编译。这将改善引用程序的编译速度。即使它增加了构建过程的复杂度。
以下几步可以提高解析速度:
以下几个实用的工具通过在内存中进行代码的编译和资源的提供,但并不写入磁盘来提高性能:
需要注意在不同的devtool的设置,会导致不同的性能差异。
在大多数情况下,cheap-module-eval-source-map是最好的选择。
某些实用工具,plugins和loaders都只能在构建生产环境时才使用。例如,在开发时使用UglifyJsPlugin来压缩和修改代码是没有意义的。以下这些工具在开发中通常被排除在外:
webpack只会在文件系统中生成已更新的chunk。应当在生成入口chunk时,尽量减少入口chunk的体积,以提高性能。
不要为了非常小的性能增益,牺牲了你应用程序的质量!!请注意,在大多数情况下优化代码质量,比构建性能更重要。
当进行多个编译时,以下工具可以帮助到你:
项目中的preset/plugins数量最小化
node-sass中有个来自Node.js线程池的阻塞线程的bug。当使用thread-loader时,需要设置workParallelJobs: 2
在webpack.config.js配置中,需要对plugins中的CleanWebpackPlugin的根路径进行修改,可以通过配置root参数。
....
plugins: [
new CleanWebpackPlugin(['dist'], {
root: path.resolve(__dirname, '../')
})
]
....
webpack 在前端工程中随处可见,当前流行的 vue, react, weex 等解决方案都推崇 webpack 作为打包工具。前端工具云集的时代,这是你值得选择的之一。
webpack是前端工程构建的一套工具,为什么一个程序称之为一套呢,是因为webpack其实是npm的一个模块,使用起来的话,这期间还需要很多其它模块来进行支持,所以我称之为一套工具。
本文从一个小Demo开始,通过不断增加功能来说明webpack的基本配置,只针对新手。webpack基本的配置就可以熟悉了,会引入loader,配置loader选项,会设置alias,会用plugins差不多。
Plugins是webpack的基础,我们都知道webpage的plugin是基于事件机制工作的,这样最大的好处是易于扩展。讲解如果扩展内置插件和其他插件,以及我们常用的Plugins插件
webpack技巧的总结:进度汇报、压缩、复数文件打包、分离app文件与第三方库文件、资源映射、输出css文件、开发模式、分析包的大小、更小的react项目、更小的Lodash、引入文件夹中所有文件、清除extract-text-webpack-plugin日志。
Webpack 作为目前最流行的前端构建工具之一,在 vue/react 等 Framework 的生态圈中都占据重要地位。在开发现代 Web 应用的过程中,Webpack 和我们的开发过程和发布过程都息息相关,如何改善 Webpack 构建打包的性能也关系到我们开发和发布部署的效率。
新版 Webpack 中我们所做的每一个更新目的都在于此,为了当大家在使用 Webpack 的时候敏捷连续毫无顿挫感。 webpack 4 进行构建性能测试,得出的结果非常有趣。结果很惊人,构建时间降低了 60%-98%!
Webpack 是一个现代 JavaScript 应用程序的模块打包器 (module bundler) 。当 Webpack 处理应用程序时,它会递归地构建一个依赖关系图,其中包含应用程序需要的每个模块
Tobias Koppers是一位自由软件开发者,家住德国纽伦堡。他因写出webpack这个已有数百万开发者使用的开源软件而名噪一时。他目前专注于JavaScript和开源项目。以下是我对他个人的专访,希望对大家有所启发。
本文讲述css-loader开启css模块功能之后,如何与引用的npm包中样式文件不产生冲突。比如antd-mobilenpm包的引入。在不做特殊处理的前提下,样式文件将会被转译成css module。
内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!