文章目录
1、webpack是什么
- WebPack 是一个模块打包工具,可以使用WebPack管理模块,并分析模块间的依赖关系,最终编绎输出模块为HTML、JavaScript、CSS以及各种静态文件(图片、字体等),让开发过程更加高效。
- 对于不同类型的资源,webpack有对应的模块加载器loader,比如说,
CSS
解析CSS的css-loader、style-loader,
解析less的less-loader,sass的sass-loader,
JS
解析将 TypeScript 转换成 JavaScript的ts-loader,
解析ES6为ES5的babel-loader,
解析JavaScript 代码规范的eslint-loader
Vue
解析.vue文件的vue-loader、
静态资源:音视频、文件、json
解析常用图片以及音视频资源的url-loader、
解析文件的file-loader,
解析 JSON 文件的json-loader,
2、webpack的基本功能(也就是各种loader的作用)
-
代码转换:TypeScript 编译成 JavaScript、ES6转ES5、SCSS 编译成 CSS 等等(
各种loader
) -
代码语法检测:自动检测代码是否符合语法 (
eslint-loader
) -
代码分割:打包代码时,可以将代码切割成不同的chunk(块),实现按需加载,降低了初始化时间,提升了首屏渲染效率
-
监测代码更新,自动编译,刷新页面:监听本地源代码的变化,自动构建,刷新浏览器(
自动刷新
) -
自动发布:更新完代码后,自动构建出线上发布代码并传输给发布系统(没用过)。
-
文件压缩:压缩 JavaScript、CSS、HTML 代码,缩小文件体积(
比如说,打包后的js、css、html文件会去掉代码之间的空隔,紧凑显示
) -
模块合并:由于模块化的开发,一个页面可能会由多个模块组成,所以编译时需要把各个模块合并成一个文件(
模块化开发引出的功能
)
3、webpack的两大特色
-
自动分割(code splitting)
code splitting,即打包代码时,可以将代码切割成不同的chunk(块),实现按需加载,降低了初始化时间,提升了首屏渲染效率
-
loader 加载器可以处理各种类型的静态文件,并且支持串联操作
4、webpack配制说明
Webpack运行在node.js环境下,它的配置文件webpack.config.js遵循CommonJS规范,最终export出一个json对象。
webpack.config.js基础配置说明:
- entry,指定了模块的入口,它让源文件加入构建流程中被webpack控制。
- output,配置输出文件的存放位置、文件名、文件基础路径publicPath。
- module,配置各种类型文件的解析规则,比如说.vue文件、.js文件。
- rosolve,配置
alias(别名)
,或者定义寻找模块的规则。 - plugins,配置扩展插件,扩展webpack的更多功能。
- devServer,实现本地http服务等。
webpack.config.js基础配置项:
module.exports = {
context: path.resolve(__dirname, '../'),
entry: {
app: ['babel-polyfill','./src/main.js']
},
output: {
path: config.build.assetsRoot,
filename: '[name].js',
publicPath: process.env.NODE_ENV === 'production'
? config.build.assetsPublicPath
: config.dev.assetsPublicPath
},
resolve: {
extensions: ['.js', '.vue', '.json'], // 当找不到模块时,尝试从后进行寻找
alias: { //别名
'vue$': 'vue/dist/vue.esm.js',
'@': resolve('src')
}
},
// 排除模块,下面的模块不会编译到 webpack 打包后的文件中
externals: {
"vue": "Vue",
"vuex": "Vuex",
"vue-router": "VueRouter",
"lodash": "_",
"echarts": "echarts"
},
plugins: [
// 全局模块对象
new webpack.ProvidePlugin({
"Vue": "vue",
"Vuex": "vuex",
"VueRouter": "vue-router",
"_": "lodash",
"echarts": "echarts"
})
],
module: {
rules: [
...(config.dev.useEslint ? [createLintingRule()] : []),
{
test: /\.vue$/,
loader: 'vue-loader',
options: vueLoaderConfig
},
{
test: /\.js$/,
loader: 'babel-loader',
include: [resolve('src'), resolve('test'), resolve('node_modules/webpack-dev-server/client')]
},
{
test: /\.scss/,
loader: ['style','css','scss']
},
{
test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('img/[name].[hash:7].[ext]')
}
},
{
test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('media/[name].[hash:7].[ext]')
}
},
{
test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/,
loader: 'url-loader',
options: {
limit: 10000,
name: utils.assetsPath('fonts/[name].[hash:7].[ext]')
}
}
]
},
node: {
// prevent webpack from injecting useless setImmediate polyfill because Vue
// source contains it (although only uses it if it's native).
setImmediate: false,
// prevent webpack from injecting mocks to Node native modules
// that does not make sense for the client
dgram: 'empty',
fs: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty'
}
}
4、webpack打包流程
-
从入口(entry) 开始,递归转换入口文件所依赖的module
-
每找到一个module,就根据对应的loader去转换这个module
-
然后,再对当前module依赖的所有module进行转换,如果子module还有依赖的话,再转换,直至没有依赖
-
其次,以入口文件(entry)为单位进行分组,一个entry和其所有依赖的module被分到一个块(Chunk)。
-
最后,Webpack会把所有Chunk转换成文件输出,在整个流程中Webpack会在恰当的时机执行plugin里定义的扩展插件。
5、有哪些常见的Plugin(插件)
5.1、webpack内置的插件
-
ProvidePlugin
:将指定模块暴露到全局,使用的时候就不需要再import和require,比如说jquery;plugins: [ new webpack.ProvidePlugin({ jQuery: "jquery", $: "jquery" }), // new HardSourceWebpackPlugin() ]
-
DefinePlugin
:允许在编译时将你代码中的变量替换为其他值或表达式,比如说Vue中生产、开发环境的判断,所用的process.env;plugins: [ new webpack.DefinePlugin({ 'process.env': require('../config/dev.env') }) ]
-
HotModuleReplacementPlugin
:热更新功能plugins:[ new webpack.HotModuleReplacementPlugin(), ]
-
CommonsChunkPlugin
: 主要是用来提取第三方库和公共模块,避免首屏加载的bundle文件体积过大,从而导致加载时间过长。plugins:[ new webpack.optimize.CommonsChunkPlugin({ name: 'vendor', minChunks (module) { } }), ]
5.2、webpack的第三方插件
-
copy-webpack-plugin
: 将单个文件或整个目录复制到打包后的目录。
第三方插件需要手动安装 npm install copy-webpack-plugin --save-devconst CopyPlugin = require('copy-webpack-plugin'); modules.exports = { plugins:[ new CopyWebpackPlugin([ { from: path.resolve(__dirname, '../static'), to: config.dev.assetsSubDirectory, ignore: ['.*'] } ]) ] }
-
clean-webpack-plugin
: 目录清理 -
html-webpack-plugin
:该插件将为你生成一个 HTML5 文件, 在 body 中使用 script 标签引入你所有 webpack 生成的 bundle。const HtmlWebpackPlugin = require('html-webpack-plugin') modules.exports = { plugins:[ new HtmlWebpackPlugin({ filename: 'index.html', template: 'index.html', inject: true }), ] }
-
uglifyjs-webpack-plugin
:压缩代码,同时可以去掉代码中的debugger、console.logconst UglifyJsPlugin = require('uglifyjs-webpack-plugin') modules.exports = { plugins:[ new UglifyJsPlugin({ uglifyOptions: { compress: { warnings: false, drop_debugger:true, drop_console: true } }, sourceMap: config.build.productionSourceMap, parallel: true }), ] }
-
compression-webpack-plugin
: 压缩指定类型的文件为gzip 文件,以部署在服务器上时,加载页面时,传输时使用gzip文件,浏览器自行解析。(gzip文件的体积比正常文件体积小3-5倍)const CompressionWebpackPlugin = require('compression-webpack-plugin') modules.exports = { plugins:[ new CompressionWebpackPlugin({ asset: '[path].gz[query]', algorithm: 'gzip', test: /\.(css)|(js)$/, threshold: 10240, // 10240字节 = 10K minRatio: 0.8 }) ] }
-
hard-source-webpack-plugin
: 利用缓存,提高打包与启动项目的速度;const HardSourceWebpackPlugin = require('hard-source-webpack-plugin'); moudles.exports = { plugins: [ new HardSourceWebpackPlugin() ] }
-
extract-text-webpack-plugin
: 抽离css样式,防止将样式打包在js中引起页面样式加载错乱的现象。const ExtractTextPlugin = require('extract-text-webpack-plugin') modules.exports = { plugins:[ new ExtractTextPlugin({ filename: utils.assetsPath('css/[name].[contenthash].css'), allChunks: true, }), ] }
-
mini-css-extract-plugin
: 分离样式文件,CSS 提取为独立文件,支持按需加载;
6、说一说Loader和Plugin的区别
-
功能不同:
Loader 本质就是一个函数,对接收到的文件进行转换
,比如将ts转换成js,将scss转换成css等。
Plugin 是webpack的插件,可以扩展 Webpack 的功能。 -
运行时机不同
loader运行在打包文件之前,对文件进行预处理;plugins 运行在loader结束后,webpack打包的整个过程中,它是
基于事件机制,监听webpack打包过程中的某些节点,从而执行相应任务,进而改变输出。
7、Webpack 的热更新原理
-
是什么
Webpack 的热更新又称热替换(Hot Module Replacement),缩写为 HMR。 这个机制可以做到不用刷新浏览器而将新变更的模块替换掉旧的模块。 -
核心
热更新的核心就是客户端与服务端建立的websocket连接,
服务端监听文件变化,编译后再推送给客户端告之其哪些地方改变了,最终客户端发送ajax请求,获取最新资源,
使用文件系统替换修改的内容实现局部更新。
8、如何优化 Webpack 的构建速度
-
使用高版本的 Webpack 和 Node.js
-
压缩代码
1). 通过 uglifyjs-webpack-plugin, 压缩JS代码
2). 通过 mini-css-extract-plugin ,分离 CSS 代码到单独文件,
3). 通过 css-loader 的 minimize 选项开启 cssnano 压缩 CSS -
压缩图片: image-webpack-loader
-
多线程/多进程构建:thread-loader、HappyPack
-
缩小打包作用域
1). exclude/include (确定 loader 规则范围)
2). resolve.modules 指明第三方模块的绝对路径 (减少不必要的查找)
3). resolve.mainFields 只采用 main 字段作为入口文件描述字段 (减少搜索步骤,需要考虑到所有运行时依赖的第三方模块的入口文件描述字段)
4). resolve.extensions 尽可能减少后缀尝试的可能性
5). noParse 对完全不需要解析的库进行忽略 (不去解析但仍会打包到 bundle 中,注意被忽略掉的文件里不应该包含 import、require、define 等模块化语句)
6). ignorePlugin (完全排除模块)
7). 合理使用alias -
提取页面公共资源, 基础包分离
1). 使用 html-webpack-externals-plugin,将基础包通过 CDN 引入,不打入 bundle 中。
2). Webpack4内置了 optimization.SplitChunks、optimization.runtimeChunk 进行(公共脚本、基础包、页面公共文件)分离 ,替代了 CommonsChunkPlugin 插件。CommonsChunkPlugin在拆分模块时,会包含重复的代码,webpack4优化了这一块。 -
充分利用缓存提升二次构建速度:
1). babel-loader 开启缓存
2). terser-webpack-plugin 开启缓存
3). 使用 hard-source-webpack-plugin -
Tree shaking
打包过程中检测工程中没有引用过的模块并进行标记,在资源压缩时将它们从最终的bundle中去掉(只能对ES6 Modlue生效)
开发中尽可能使用ES6 Module的模块,提高tree shaking效率 禁用 babel-loader 的模块依赖解析,否则Webpack 接收到的就都是转换过的 CommonJS 形式的模块,无法进行 tree-shaking
使用PurifyCSS(不在维护) 或者 uncss 去除无用 CSS 代码
purgecss-webpack-plugin 和 mini-css-extract-plugin配合使用(建议)
-
Scope hoisting
构建后的代码会存在大量闭包,造成体积增大,运行代码时创建的函数作用域变多,内存开销变大。Scope hoisting 将所有模块的代码按照引用顺序放在一个函数作用域里,然后适当的重命名一些变量以防止变量名冲突
9、webpack 和 gulp 区别
gulp
强调的是前端开发的工作流程,我们可以通过配置一系列的 task,定义 task 处理的事务(例如文件压缩合并、雪碧图、启动 server、版本控制等),然后定义执行顺序, 来让 gulp 执行这些 task,从而构建项目的整个前端开发流程。webpack
是一个前端模块化方案,更侧重模块打包,我们可以把开发中的所有资源(图 片、js 文件、css 文件等)都看成模块,通过 loader(加载器)和 plugins(插件)对资源 进行处理,打包成符合生产环境部署的前端资源。
参考链接:http://www.atguigu.com/mst/html/gp/17644.html