一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第4天,点击查看活动详情。
webpack是什么?
- 一种前端资源构建工具,一个静态模块打包器(nodule bundle)
- 前端所有资源文件(js/json/css/img…)都会作为模块处理
- 它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)
为什么需要webpack?
现在很多网页其实可以看做是功能丰富的应用,它们拥有着复杂的JavaScript代码和一大堆依赖包。为了简化开发的复杂度,前端社区涌现出了很多好的实践方法,eg:
- 模块化,让我们可以把复杂的程序细化为小的文件;
- 类似于TypeScript这种在JavaScript基础上拓展的开发语言:使我们能够实现目前版本的JavaScript不能直接使用的特性,并且之后还能能装换为JavaScript文件使浏览器可以识别;
- scss,less等CSS预处理器
...
这些改进确实大大的提高了我们的开发效率,但是利用它们开发的文件往往需要进行额外的处理才能让浏览器识别,而手动处理又是非常繁琐的,这就为WebPack类的工具的出现提供了需求
webpack组成
- Entry(入口函数)
- 入口起点(entry point)指示 webpack 应该使用哪个模块,来作为构建其内部依赖图的开始
- Output(输出函数)
- output 属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件,默认值为 ./dist
- loader
- loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理
webpack.config.js
const path = require('path');
const config = {
output: {
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
}
};
module.exports = config;
- plugins
- loader 被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩,一直到重新定义环境中的变量。插件接口功能极其强大,可以用来处理各种各样的任务
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 通过 npm 安装
const webpack = require('webpack'); // 用于访问内置插件
const config = {
module: {
rules: [
{ test: /\.txt$/, use: 'raw-loader' }
]
},
plugins: [
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
module.exports = config;
- Mode
- 模式(Mode)指示 Webpack 使用相应模式的配置,只有development(开发环境)和production(生产环境)两种模式
webpack热更新
热更新又称热替换(Hot Module Replacement),缩写为HMR,基于devServer,生产环境不需要devServer,所以生产环境不能用HMR功能
作用: 优化打包构建速度,一个模块发生变化,只会重新打包这一个模块(而不是打包所有模块),极大提升构建速度
样式文件:可以使用HMR功能,因为style-loader内部实现了
JS文件:默认没有HMR功能,需要修改js代码,添加支持HMR功能。入口文件做不了HMR功能,只能处理非入口js文件
HTML文件:默认没有HMR功能,同时会导致 html 文件不能热更新(即修改没有任何反应)
解决方案:
修改entry入口,将html文件引入
entry:['./src/js/index.js','./src/index.html']
不用做HMR功能,因为只有一个html文件
有哪些常见的Loader?它们是解决什么问题的?
- css-loader:将 css 文件变成 CommonJS 模块加载 js 中,里面内容是样式字符串
- style-loader:创建 style 标签,将 js 中的样式资源插入进行,添加到 head 中生效
- url-loader:在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
- file-loader:打包其他资源(除了css/js/html 资源)
- html-loader:处理 html 文件中的 img
- babel-loader:把 ES6 转换成 ES5
- eslint-loader:通过 ESLint 检查 JavaScript 代码
有哪些常见的Plugin?它们是解决什么问题的?
- html-webpack-plugin:可以复制一个有结构的html文件,并自动引入打包输出的所有资源(JS/CSS)
- clean-webpack-plugin:重新打包自动清空 dist 目录
- mini-css-extract-plugin:提取 js 中的 css 成单独文件
- optimize-css-assets-webpack-plugin:压缩css
- uglifyjs-webpack-plugin:压缩js
- commons-chunk-plugin:提取公共代码
webpack的构建流程
- 初始化参数:从配置文件和 Shell 语句中读取与合并参数,得出最终的参数;
- 开始编译:用上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执行对象的 run 方法开始执行编译;
- 确定入口:根据配置中的 entry 找出所有的入口文件;
- 编译模块:从入口文件出发,调用所有配置的 Loader 对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文件都经过了本步骤的处理;
- 完成模块编译:在经过第4步使用 Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
- 输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表,这步是可以修改输出内容的最后机会;
- 输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名,把文件内容写入到文件系统