webpack配置之代码优化
前面的话
前面介绍了webpack的基本配置,本文将详细介绍webpack中关于代码优化的配置
打包公共代码
CommonsChunkPlugin 插件,是一个可选的用于建立一个独立文件(又称作 chunk)的功能,这个文件包括多个入口 chunk 的公共模块。通过将公共模块拆出来,最终合成的文件能够在最开始的时候加载一次,便存到缓存中供后续使用。这会带来速度上的提升,因为浏览器会迅速将公共的代码从缓存中取出来,而不是每次访问一个新页面时,再去加载一个更大的文件
new webpack.optimize.CommonsChunkPlugin(options)
【配置项】
{
name: string, // or
names: string[],
// common chunk 的名称
filename: string,
// common chunk 的文件名模板。可以包含与 `output.filename` 相同的占位符
minChunks: number|Infinity|function(module, count) -> boolean,
// 在传入公共chunk(commons chunk) 之前所需要包含的最少数量的 chunks 。
// 数量必须大于等于2,或者少于等于 chunks的数量
chunks: string[],
// 通过 chunk name 去选择 chunks 的来源。chunk 必须是 公共chunk 的子模块。
children: boolean,
// 如果设置为 `true`,所有公共chunk 的子模块都会被选择
deepChildren: boolean,
// If `true` all descendants of the commons chunk are selected
async: boolean|string,
// 如果设置为 `true`,一个异步的公共chunk 会作为 `options.name` 的子模块,和 `options.chunks` 的兄弟模块被创建。
minSize: number,
// 在 公共chunk 被创建立之前,所有公共模块 (common module) 的最少大小。
}
【提取公共代码】
new webpack.optimize.CommonsChunkPlugin({
name: "commons",
// ( 公共chunk(commnons chunk) 的名称)
filename: "commons.js",
// ( 公共chunk 的文件名)
})
【明确第三方库chunk】
entry: {
vendor: ["jquery", "other-lib"],
app: "./entry"
},
plugins: [
new webpack.optimize.CommonsChunkPlugin({
name: "vendor",
minChunks: Infinity,
})
]
【将公共模块打包进父 chunk】
new webpack.optimize.CommonsChunkPlugin({
children: true,
})
【额外的异步公共chunk】
new webpack.optimize.CommonsChunkPlugin({
name: "app",
// or
names: ["app", "subPageA"]
children: true,
async: true,
minChunks: ,
})
【wepack4】
webpack 4 将移除 CommonsChunkPlugin, 取而代之的是两个新的配置项 optimization.splitChunks 和 optimization.runtimeChunk
通过设置 optimization.splitChunks.chunks: "all" 来启动默认的代码分割配置项
当满足如下条件时,webpack 会自动打包 chunks:
当前模块是公共模块(多处引用)或者模块来自 node_modules
当前模块大小大于 30kb
如果此模块是按需加载,并行请求的最大数量小于等于
如果此模块在初始页面加载,并行请求的最大数量小于等于
通过设置 optimization.runtimeChunk: true 来为每一个入口默认添加一个只包含 runtime 的 chunk
动态导入
上面介绍的CommonsChunkPlugin可以去重和分离chunk。而本节介绍的动态导入,则是通过模块的内联函数调用来分离代码
webpack 提供了两个类似的技术。对于动态导入,第一种,也是优先选择的方式是,使用符合 ECMAScript 提案 的 import() 语法。第二种,则是使用 webpack 特定的 require.ensure
下面来使用import()语法来进行动态导入
const path = require('path');
const HTMLWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
index: './src/index.js'
},
plugins: [
new HTMLWebpackPlugin({
title: 'Code Splitting'
})
],
output: {
filename: '[name].bundle.js',
chunkFilename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
下面来动态导入loadsh
function getComponent() {
return import(/* webpackChunkName: "lodash" */ 'lodash').then(_ => {
var element = document.createElement('div');
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
return element;
}).catch(error => 'An error occurred while loading the component');
} getComponent().then(component => {
document.body.appendChild(component);
})
在注释中使用了 webpackChunkName。这样做会导致bundle 被命名为 lodash.bundle.js ,而不是 [id].bundle.js
懒加载
懒加载或者按需加载,是一种很好的优化网页或应用的方式。这种方式实际上是先把你的代码在一些逻辑断点处分离开,然后在一些代码块中完成某些操作后,立即引用或即将引用另外一些新的代码块。这样加快了应用的初始加载速度,减轻了它的总体体积,因为某些代码块可能永远不会被加载
上面通过动态导入的loadsh确实会在脚本运行的时候产生一个分离的代码块 lodash.bundle.js ,在技术概念上“懒加载”它。问题是加载这个包并不需要用户的交互 -- 意思是每次加载页面的时候都会请求它
下面来增加一个交互,当用户点击按钮的时候用 console 打印一些文字。但是会等到第一次交互的时候再加载那个代码块(print.js)
//print.js
console.log('The print.js module has loaded! See the network tab in dev tools...');
export default () => {
console.log('Button Clicked: Here\'s "some text"!');
}
//index.js
import _ from 'lodash';
function component() {
var element = document.createElement('div');
var button = document.createElement('button');
var br = document.createElement('br');
button.innerHTML = 'Click me and look at the console!';
element.innerHTML = _.join(['Hello', 'webpack'], ' ');
element.appendChild(br);
element.appendChild(button);
button.onclick = e => import(/* webpackChunkName: "print" */ './print').then(module => {
var print = module.default;
print();
});
return element;
}
document.body.appendChild(component());
剔除无用代码
tree shaking 是一个术语,通常用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。它依赖于 ES2015 模块系统中的静态结构特性,例如 import 和 export。这个术语和概念实际上是兴起于 ES2015 模块打包工具 rollup
【JS】
JS的tree shaking主要通过uglifyjs插件来完成
npm install --save-dev uglifyjs-webpack-plugin
const path = require('path');
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
plugins: [
new UglifyJSPlugin()
]
};
【CSS】
CSS的tree shaking主要通过purify CSS来实现的
npm i -D purifycss-webpack purify-css
const path = require('path');
const glob = require('glob');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const PurifyCSSPlugin = require('purifycss-webpack');
module.exports = {
entry: {...},
output: {...},
module: {
rules: [
{
test: /\.css$/,
loader: ExtractTextPlugin.extract({
fallbackLoader: 'style-loader',
loader: 'css-loader'
})
}
]
},
plugins: [
new ExtractTextPlugin('[name].[contenthash].css'),
// Make sure this is after ExtractTextPlugin!
new PurifyCSSPlugin({
// Give paths to parse for rules. These should be absolute!
paths: glob.sync(path.join(__dirname, 'app/*.html')),
})
]
};
如果要设置多路径,则需要将glob换成glob-all
const glob = require('glob-all');
paths: glob.sync([
path.join(__dirname, '.php'),
path.join(__dirname, 'partials/.php')
])
模块热更新
模块热更新,又称为模块热替换,HMR(Hot Module Replacement)。在应用程序运行过程中替换、添加或删除模块,无需重新加载页面,极大地加速了开发时间
启用此功能实际上相当简单。而我们要做的,就是更新 webpack-dev-server 的配置,和使用 webpack 内置的 HMR 插件。此外,还添加了NamedModulesPlugin,以便更容易查看要修补(patch)的依赖
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require('webpack');
module.exports = {
entry: {
app: './src/index.js'
},
devtool: 'inline-source-map',
devServer: {
contentBase: './dist',
hot: true
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Hot Module Replacement'
}),
new webpack.NamedModulesPlugin(),
new webpack.HotModuleReplacementPlugin()
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
长缓存优化
【使用chunkhash】
将hash替换为chunkhash,这样当chunk不变时,缓存依然有效
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Caching'
})
],
output: {
filename: '[name].[chunkhash].js',
path: path.resolve(__dirname, 'dist')
}
};
【提取模板】
CommonsChunkPlugin 可以用于将模块分离到单独的文件中。还能够在每次修改后的构建结果中,将 webpack 的样板(boilerplate)和 manifest 提取出来。通过指定 entry 配置中未用到的名称,此插件会自动将我们需要的内容提取到单独的包中
const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Caching'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest'
})
],
output: {
filename: '[name].[chunkhash].js',
path: path.resolve(__dirname, 'dist')
}
};
将第三方库(library)(例如 lodash 或 react)提取到单独的 vendor chunk 文件中,是比较推荐的做法,这是因为,它们很少像本地的源代码那样频繁修改。因此通过实现以上步骤,利用客户端的长效缓存机制,可以通过命中缓存来消除请求,并减少向服务器获取资源,同时还能保证客户端代码和服务器端代码版本一致。这可以通过使用新的 entry(入口) 起点,以及再额外配置一个 CommonsChunkPlugin 实例的组合方式来实现
var path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
main: './src/index.js',
vendor: [
'lodash'
]
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Caching'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest'
})
],
output: {
filename: '[name].[chunkhash].js',
path: path.resolve(__dirname, 'dist')
}
};
[注意]CommonsChunkPlugin 的 'vendor' 实例,必须在 'manifest' 实例之前引入
【使用Name而不是id】
每个 module.id 会基于默认的解析顺序(resolve order)进行增量。也就是说,当解析顺序发生变化,ID 也会随之改变
下面来使用两个插件解决这个问题。第一个插件是 NamedModulesPlugin,将使用模块的路径,而不是数字标识符。虽然此插件有助于在开发过程中输出结果的可读性,然而执行时间会长一些。第二个选择是使用 HashedModuleIdsPlugin,推荐用于生产环境构建
const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: {
main: './src/index.js',
vendor: [
'lodash'
]
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Caching'
}),
new webpack.HashedModuleIdsPlugin(),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest'
})
],
output: {
filename: '[name].[chunkhash].js',
path: path.resolve(__dirname, 'dist')
}
};
公用代码内联
使用html-webpack-inline-chunk-plugin插件将mainfest.js内联到html文件中
$ npm install html-webpack-inline-chunk-plugin --save-dev
const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const InlineChunkWebpackPlugin = require('html-webpack-inline-chunk-plugin');
module.exports = {
entry: {
main: './src/index.js',
vendor: [
'lodash'
]
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Caching',
inlineSource: '.(js|css)$'
}),
new webpack.HashedModuleIdsPlugin(),
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor'
}),
new webpack.optimize.CommonsChunkPlugin({
name: 'manifest'
}),
new InlineChunkWebpackPlugin({
inlineChunks: ['manifest']
})
],
output: {
filename: '[name].[chunkhash].js',
path: path.resolve(__dirname, 'dist')
}
};
webpack配置之代码优化的更多相关文章
- [webpack] 配置react+es6开发环境
写在前面 每次开新项目都要重新安装需要的包,简单记录一下. 以下仅包含最简单的功能: 编译react 编译es6 打包src中入口文件index.js至dist webpack配置react+es6开 ...
- webpack配置详解
webpack配置详解 先点个赞吧,再挨个点下面的连接,觉得不值这个赞的回来骂我啊. Webpack傻瓜式指南(一) Webpack傻瓜指南(二)开发和部署技巧 Webpack傻瓜式指南 原生的官网详 ...
- Webpack配置示例和详细说明
/* * 请使用最新版本nodejs * 默认配置,是按生产环境的要求设置,也就是使用 webpack -p 命令就可以生成正式上线版本. * 也可以使用 webpack -d -w 命令,生成用于开 ...
- vue-cli#2.0 webpack 配置分析
目录结构: ├── README.md ├── build │ ├── build.js │ ├── check-versions.js │ ├── dev-client.js │ ├── dev-s ...
- webpack配置这一篇就够
最近看了一篇好文,根据这个文章重新梳理了一遍webpack打包过程,以前的一些问题也都清楚了,在这里分享一下,同时自己也做了一些小的调整 原文链接:http://www.jianshu.com/p/4 ...
- webpack配置报错:invalid configuration object.webpack has been initialisted using a configuration objcet that does not match thie API schema
最近接收了别人的项目,webpack配置总是报错如下:最后找到了解决办法,在此分享一下: 错误情况: 解决办法: 将package.json里面的colors删除掉即可
- 前端工程化(二)---webpack配置
导航 前端工程化(一)---工程基础目录搭建 前端工程化(二)---webpack配置 前端工程化(三)---Vue的开发模式 前端工程化(四)---helloWord 继续上一遍的配置,本节主要记录 ...
- vue全家桶安装以及修改webpack配置新增vue项目启动方式
一.安装node环境(自带npm) 下载地址 二.替换下载源 // 淘宝 NPM 镜像 npm install -g cnpm --registry=https://registry.npm.taob ...
- vue-cli中webpack配置详解
vue-cli是构建vue单页应用的脚手架,命令行输入vue init <template-name> <project-name>从而自动生成的项目模板,比较常用的模板有we ...
随机推荐
- Spark性能调优
Spark性能优化指南——基础篇 https://tech.meituan.com/spark-tuning-basic.html Spark性能优化指南——高级篇 https://tech.meit ...
- CentOS 6.5下RPM方式(重新)安装MySQL 5.7.21从头到尾篇
强烈推荐参阅这一篇教程 https://www.cnblogs.com/kevingrace/p/8340690.html 下面我写的仅供参考 今天把Mysql5.1升级到了5.7,浪费了一天为了避 ...
- JS 异步系列 —— Promise 札记
Promise 研究 Promise 的动机大体有以下几点: 对其 api 的不熟悉以及对实现机制的好奇; 很多库(比如 fetch)是基于 Promise 封装的,那么要了解这些库的前置条件得先熟悉 ...
- git在vs2017中的使用
对于习惯了右键提交源代码的道友来说,敲命令行真的蓝瘦香菇.所幸17里集成了Git插件,用起来还是挺方便的. 1.本地安装git,工具还是要有的,主要用于配置环境,ssh配置一下.就不用每次都去连接了. ...
- Mysql 中的MVCC原理,undo日志的依赖
一. MVCC 原理了解 原文点击:MVCC原理浅析 读锁: 也叫共享锁.S锁,若事务T对数据对象A加上S锁,则事务T可以读A但不能修改A,其他事务只能再对A加S锁,而不能加X锁,直到T释放A上的 ...
- Windows之系统自带截屏快捷键
Windows之系统自带截屏快捷键 现在我们都习惯了使用QQ截屏,但是有时候电脑没有网络,也就意味着无法登陆QQ,在这个时候再有截屏的需求时,我们就束手无策了. 截取全屏 现在我说以个Windows系 ...
- Vue父子传值
昨天创建完项目以后,今日首先使用项目来做一个简单的导航栏体会一下Vue的使用 1.项目的结构: 2.首先在Vheader.Vue中编辑代码: <template> <header c ...
- Java 学习使用常见的开源连接池
目录 连接池介绍 自定义连接池 JDBC Tomcat Pool DBCP(DataBase Connection Pool) 使用配置文件来设置DBCP C3P0 Druid 连接池介绍 在说连接池 ...
- 【学习总结】Git学习-参考廖雪峰老师教程六-分支管理
学习总结之Git学习-总 目录: 一.Git简介 二.安装Git 三.创建版本库 四.时光机穿梭 五.远程仓库 六.分支管理 七.标签管理 八.使用GitHub 九.使用码云 十.自定义Git 期末总 ...
- 【问题解决方案】之 关于某江加密视频swf专用播放器仍无法播放的问题
前言: 从pt上下载了一些语言学习的视频之后一直打不开,百度谷歌了若干种方法仍然无解.无奈放弃. 某日从百度知道里又看到一个方法,试了一下,居然灵了.呜呼哀哉.赶紧记下来. 原方法链接:https:/ ...