New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
webpack2 终极优化 #2
Comments
你好,你给出的webpack配置链接好像是失效的?在知乎和这里都转不过去。 |
你是说 webpack整体的配置 这个链接吗? |
噢!可以了,竟然要翻个墙才能访问gits。 |
谢谢你的文章~ |
感谢楼主文章 CommonsChunkPlugin 抽取公共代码 这里有点模糊
|
@gwuhaolin 在环境变量 NODE_ENV 等于 production 的时候UglifyJs会认为if语句里的是死代码在压缩代码时删掉。 |
如果你的应用由多个单页应用组成,由于把多个单页应用都依赖的代码抽离出来放到一个单独的文件里,用户在这几个单页应用之间切换时公共的代码由于缓存机制只会被加载一次,这有利于提升网页加载速度。如果你的应用只由一个单页应用组成,那么就没必要做公用代码提取。
你这里应该是指的代码分割,目的是把网页首屏不需要的展示的对应的那部分代码分割出来,等用户操作到一定的步骤时在异步加载被分割出来的代码,这有利于优化首屏加载速度。 |
我们经常会通过 // Webpack Hot Module Replace
if (process.env.NODE_ENV !== 'production') {
if (module.hot) {
module.hot.accept();
}
} 这里面的原理是这样的,要分两种情况:
// Webpack Hot Module Replace
if (false) {
if (module.hot) {
module.hot.accept();
}
} 之后 UglifyJs 会删掉所有确定不可能执行的代码,例如以上的 |
@gwuhaolin 多谢你的解答
// split vendor js into its own file
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
minChunks: function (module, count) {
// any required modules inside node_modules are extracted to vendor
return (
module.resource &&
/\.js$/.test(module.resource) &&
module.resource.indexOf(
path.join(__dirname, '../node_modules')
) === 0
)
}
}),
// extract webpack runtime and module manifest to its own file in order to
// prevent vendor hash from being updated whenever app bundle is updated
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest',
chunks: ['vendor']
}), 这里对vendor能看出是对第三方代码的提取 manifest提取的是什么东西 不是很理解 |
讲的很实用 |
你好,能问下文章最后的 分析输出结果 的详细操作么? |
有没有基于Webpack 4的优化 哈哈 |
webpack是当下最流行的js打包工具,这得益于网页应用日益复杂和js模块化的流行。webpack2增加了一些新特性也正式发布了一段时间,是时候告诉大家如何用webpack2优化你的构建让它构建出更小的文件尺寸和更好的开发体验。
优化输出
打包结果更小可以让网页打开速度更快以及简约宽带。可以通过这以下几点做到
压缩css
css-loader
在webpack2里默认是没有开启压缩的,最后生成的css文件里有很多空格和tab,通过配置css-loader?minimize
参数可以开启压缩输出最小的css。css的压缩实际是是通过cssnano实现的。tree-shaking
tree-shaking 是指借助es6
import export
语法静态性的特点来删掉export但是没有import过的东西。要让tree-shaking工作需要注意以下几点:import export
转换为cmd的module.export
,配置如下:import export
语法的代码。拿redux库来说,npm下载到的目录结构如下:
其中lib目录里是编译出的es5代码,es目录里是编译出的采用
import export
语法的es5代码,在redux的package.json
文件里有这两个配置:这是指这个库的入口文件的位置,所以要让webpack去读取es目录下的代码需要使用jsnext:main字段配置的入口,要做到这点webpack需要这样配置:
这会让webpack先使用jsnext:main字段,在没有时使用main字段。这样就可以优化支持tree-shaking的库。
优化 UglifyJsPlugin
webpack
--optimize-minimize
选项会开启 UglifyJsPlugin来压缩输出的js,但是默认的UglifyJsPlugin配置并没有把代码压缩到最小输出的js里还是有注释和空格,需要覆盖默认的配置:定义环境变量 NODE_ENV=production
很多库里(比如react)有部分代码是这样的:
在环境变量
NODE_ENV
等于production
的时候UglifyJs会认为if语句里的是死代码在压缩代码时删掉。使用 CommonsChunkPlugin 抽取公共代码
CommonsChunkPlugin可以提取出多个代码块都依赖的模块形成一个单独的模块。要发挥CommonsChunkPlugin的作用还需要浏览器缓存机制的配合。在应用有多个页面的场景下提取出所有页面公共的代码减少单个页面的代码,在不同页面之间切换时所有页面公共的代码之前被加载过而不必重新加载。这个方法可以非常有效的提升应用性能。
在生产环境按照文件内容md5打hash
webpack编译在生产环境出来的js、css、图片、字体这些文件应该放到CDN上,再根据文件内容的md5命名文件,利用缓存机制用户只需要加载一次,第二次加载时就直接访问缓存。如果你之后有修改就会为对应的文件生产新的md5值。做到以上你需要这样配置:
知道以上原理后我们还可以进一步优化:利用CommonsChunkPlugin提取出使用页面都依赖的基础运行环境。比如对于最常见的react体系你可以抽出基础库
react
react-dom
redux
react-redux
到一个单独的文件而不是和其它文件放在一起打包为一个文件,这样做的好处是只要你不升级他们的版本这个文件永远不会被刷新。如果你把这些基础库和业务代码打包在一个文件里每次改动业务代码都会导致浏览器重复下载这些包含基础库的代码。以上的配置为:DedupePlugin 和 OccurrenceOrderPlugin
在webpack1里经常会使用
DedupePlugin
插件来消除重复的模块以及使用OccurrenceOrderPlugin
插件让被依赖次数更高的模块靠前分到更小的id 来达到输出更少的代码,在webpack2里这些已经这两个插件已经被移除了因为这些功能已经被内置了。除了压缩文本代码外还可以:
以上优化点只需要在构建用于生产环境代码的时候才使用,在开发环境时最好关闭因为它们很耗时。
优化开发体验
优化开发体验主要从更快的构建和更方便的功能入手。
更快的构建
缩小文件搜索范围
webpack的
resolve.modules
配置模块库(通常是指node_modules)所在的位置,在js里出现import 'redux'
这样不是相对也不是绝对路径的写法时会去node_modules目录下找。但是默认的配置会采用向上递归搜索的方式去寻找node_modules,但通常项目目录里只有一个node_modules在项目根目录,为了减少搜索我们直接写明node_modules的全路径:除此之外webpack配置loader时也可以缩小文件搜索范围。
.js
文件时就不要把test写成/\.jsx?$/
只对项目目录下src目录里的代码进行babel编译
项目目录下的所有js都会进行babel编译,包括庞大的node_modules下的js
开启 babel-loader 缓存
babel编译过程很耗时,好在babel-loader提供缓存编译结果选项,在重启webpack时不需要创新编译而是复用缓存结果减少编译流程。babel-loader缓存机制默认是关闭的,打开的配置如下:
使用 alias
resolve.alias
配置路径映射。发布到npm的库大多数都包含两个目录,一个是放着cmd模块化的lib目录,一个是把所有文件合成一个文件的dist目录,多数的入口文件是指向lib里面下的。
默认情况下webpack会去读lib目录下的入口文件再去递归加载其它依赖的文件这个过程很耗时,alias配置可以让webpack直接使用dist目录的整体文件减少文件递归解析。配置如下:
使用 noParse
module.noParse
配置哪些文件可以脱离webpack的解析。有些库是自成一体不依赖其他库的没有使用模块化的,比如jquey、momentjs、chart.js,要使用它们必须整体全部引入。
webpack是模块化打包工具完全没有必要去解析这些文件的依赖,因为它们都不依赖其它文件体积也很庞大,要忽略它们配置如下:
除此以外还有很多可以加速的方法:
更方便的功能
模块热替换
模块热替换是指在开发的过程中修改代码后不用刷新页面直接把变化的模块替换到老模块让页面呈现出最新的效果。
webpack-dev-server内置模块热替换,配置起来也很方便,下面以react应用为例,步骤如下:
--hot
参数开启模块热替换,在开启--hot
后针对css的变化是会自动热替换的,但是js涉及到复杂的逻辑还需要进一步配置。当./app发生变化或者当./app依赖的文件发生变化时会把./app编译成一个模块去替换老的,替换完毕后重新执行run函数渲染出最新的效果。
自动生成html
webpack只做了资源打包的工作还缺少把这些加载到html里运行的功能,在庞大的app里手写html去加载这些资源是很繁琐易错的,我们需要自动正确的加载打包出的资源。
webpack原生不支持这个功能于是我做了一个插件 web-webpack-plugin
具体使用点开链接看详细文档,使用大概如下:
demo
webpack配置
将会输出一个
index.html
文件,这个文件将会自动引入 entryA
和B
生成的js文件,输出的html:
输出的目录结构
管理多页面
虽然webpack适用于单页应用,但复杂的系统经常是由多个单页应用组成,每个页面一个功能模块。webpack给出了js打包方案但缺少管理多个页面的功能。 web-webpack-plugin的
AutoWebPlugin
会自动的为你的系统里每个单页应用生成一个html入口页,这个入口会自动的注入当前单页应用依赖的资源,使用它你只需如下几行代码:查看web-webpack-plugin的文档了解更多
分析输出结果
如果你对当前的配置输出或者构建速度不满意,webpack有一个工具叫做webpack analyze 以可视化的方式直观的分析构建,来进一步优化构建结果和速度。要使用它你需要在执行webpack的时候带上
--json --profile
2个参数,这代表让webpack把构建结果以json输出并带上构建性能信息,使用如下:webpack --json --profile > stats.json
会生产一个
stats.json
文件,再打开webpack analyze 上传这个文件开始分析。最后附上这篇文章所讲到的webpack整体的配置,分为开发环境的
webpack.config.js
和生产环境的webpack-dist.config.js
阅读原文
The text was updated successfully, but these errors were encountered: