这是 webpack 系列文章的十一篇, 整理了一些关于 webpack 的面试题, 对之前的内容做一次总结
webpack 官网 https://webpack.js.org/
webpack 中文网 https://www.webpackjs.com/
什么是 webpack
webpack 是一个打包模块化 JavaScript 的工具, 在 webpack 里一切文件皆模块, 通过 loader 转换文件, 通过 plugin 注入钩子, 最后输出由多个模块组合成的文件, webpack 专注构建模块化项目.
WebPack 可以看做是模块打包机: 它做的事情是, 分析你的项目结构, 找到 JavaScript 模块以及其它的一些浏览器不能直接运行的拓展语言(SCSS,TypeScript 等), 并将其打包为合适的格式以供浏览器使用.
官网的图片形象的展示了 webpack 的定义
几个常见的 loader
file-loader: 把文件输出到一个文件夹中, 在代码中通过相对 URL 去引用输出的文件
url-loader: 和 file-loader 类似, 但是能在文件很小的情况下以 base64 的方式把文件内容注入到代码中去
source-map-loader: 加载额外的 Source Map 文件, 以方便断点调试
image-loader: 加载并且压缩图片文件
babel-loader: 把 ES6 转换成 ES5
CSS-loader: 加载 CSS, 支持模块化, 压缩, 文件导入等特性
style-loader: 把 CSS 代码注入到 JavaScript 中, 通过 DOM 操作去加载 CSS.
eslint-loader: 通过 ESLint 检查 JavaScript 代码
几个常见的 plugin
define-plugin: 定义环境变量
terser-webpack-plugin: 通过 TerserPlugin 压缩 ES6 代码
html-webpack-plugin 为 HTML 文件中引入的外部资源, 可以生成创建 HTML 入口文件
mini-CSS-extract-plugin: 分离 CSS 文件
clean-webpack-plugin: 删除打包文件
happypack: 实现多线程加速编译
webpack 与 grunt,gulp 的不同?
Webpack 与 Gulp,Grunt 没有什么可比性, 它可以看作模块打包机, 通过分析你的项目结构, 找到 JavaScript 模块以及其它的一些浏览器不能直接运行的拓展语言(SCSS,TypeScript 等), 并将其转换和打包为合适的格式供浏览器使用. Gulp/Grunt 是一种能够优化前端的开发流程的工具, 而 WebPack 是一种模块化的解决方案, 不过 Webpack 的优点使得 Webpack 在很多场景下可以替代 Gulp/Grunt 类的工具.
他们的工作方式也有较大区别:
Grunt 和 Gulp 的工作方式是: 在一个配置文件中, 指明对某些文件进行类似编译, 组合, 压缩等任务的具体步骤, 工具之后可以自动替你完成这些任务.
Webpack 的工作方式是: 把你的项目当做一个整体, 通过一个给定的主文件 (如: index.JS),Webpack 将从这个文件开始找到你的项目的所有依赖文件, 使用 loaders 处理它们, 最后打包为一个(或多个) 浏览器可识别的 JavaScript 文件.
三者都是前端构建工具, grunt 和 gulp 在早期比较流行, 现在 webpack 相对来说比较主流, 不过一些轻量化的任务还是会用 gulp 来处理, 比如单独打包 CSS 文件等.
grunt 和 gulp 是基于任务和流 (Task,Stream) 的. 类似 jQuery, 找到一个 (或一类) 文件, 对其做一系列链式操作, 更新流上的数据, 整条链式操作构成了一个任务, 多个任务就构成了整个 Web 的构建流程.
webpack 是基于入口的. webpack 会自动地递归解析入口所需要加载的所有资源文件, 然后用不同的 Loader 来处理不同的文件, 用 Plugin 来扩展 webpack 功能.
所以总结一下:
从构建思路来说
gulp 和 grunt 需要开发者将整个前端构建过程拆分成多个 Task, 并合理控制所有 Task 的调用关系
webpack 需要开发者找到入口, 并需要清楚对于不同的资源应该使用什么 Loader 做何种解析和加工
对于知识背景来说
gulp 更像后端开发者的思路, 需要对于整个流程了如指掌 webpack 更倾向于前端开发者的思路
webpack 有哪些优点
专注于处理模块化的项目, 能做到开箱即用, 一步到位
可通过 plugin 扩展, 完整好用又不失灵活
使用场景不局限于 Web 开发
社区庞大活跃, 经常引入紧跟时代发展的新特性, 能为大多数场景找到已有的开源扩展
良好的开发体验
webpack 的缺点
webpack 的缺点是只能用于采用模块化开发的项目
分别介绍 bundle,chunk,module 是什么
bundle: 是由 webpack 打包出来的文件,
chunk: 代码块, 一个 chunk 由多个模块组合而成, 用于代码的合并和分割.
module: 是开发中的单个模块, 在 webpack 的世界, 一切皆模块, 一个模块对应一个文件, webpack 会从配置的 entry 中递归开始找出所有依赖的模块.
分别介绍什么是 loader? 什么是 plugin?
loader: 模块转换器, 用于将模块的原内容按照需要转成你想要的内容
plugin: 在 webpack 构建流程中的特定时机注入扩展逻辑, 来改变构建结果, 是用来自定义 webpack 打包过程的方式, 一个插件是含有 apply 方法的一个对象, 通过这个方法可以参与到整个 webpack 打包的各个流程(生命周期).
什么 是模块热更新?
模块热更新是 webpack 的一个功能, 他可以使得代码修改过后不用刷新浏览器就可以更新, 是高级版的自动刷新浏览器.
devServer 中通过 hot 属性可以控制模块的热替换
1, 通过配置文件
- const webpack = require('webpack');
- const path = require('path');
- let env = process.env.NODE_ENV == "development" ? "development" : "production";
- const config = {
- mode: env,
- devServer: {
- hot:true
- }
- }
- plugins: [
- new webpack.HotModuleReplacementPlugin(), // 热加载插件
- ],module.exports = config;
2, 通过命令行
- "scripts": {
- "test": "echo \"Error: no test specified\"&& exit 1",
- "start": "NODE_ENV=development webpack-dev-server --config webpack.develop.config.js --hot",
- },
什么是 Tree-shaking
Tree-shaking 可以用来剔除 JavaScript 中不用的死代码, 它依赖静态的 es6 模块化语法, 例如通过哦 import 和 export 导入导出, Tree-shaking 最先在 rollup 中出现, webpack 在 2.0 中将其引入, CSS 中使用 Tree-shaking 需要引入 Purify-CSS
通过 webpack 处理长缓存
浏览器在用户访问页面的时候, 为了加快加载速度, 会对用户访问的静态资源进行存储, 但是每一次代码升级或是更新, 都需要浏览器去下载新的代码, 最方便和简单的更新方式就是引入新的文件名称. 在 webpack 中可以在 output 纵输出的文件指定 chunkhash, 并且分离经常更新的代码和框架代码. 通过 NameModulesPlugin 或是 HashedModuleIdsPlugin 使再次打包文件名不变.
如何提高 webpack 的构建速度
通过 externals 配置来提取常用库
利用 DllPlugin 和 DllReferencePlugin 预编译资源模块 通过 DllPlugin 来对那些我们引用但是绝对不会修改的 NPM 包来进行预编译, 再通过 DllReferencePlugin 将预编译的模块加载进来.
使用 Happypack 实现多线程加速编译
要注意的第一点是, 它对 file-loader 和 url-loader 支持不好, 所以这两个 loader 就不需要换成 happypack 了, 其他 loader 可以类似地换一下
使用 Tree-shaking 和 Scope Hoisting 来剔除多余代码
使用 fast-Sass-loader 代替 Sass-loader
babel-loader 开启缓存
babel-loader 在执行的时候, 可能会产生一些运行期间重复的公共文件, 造成代码体积大冗余, 同时也会减慢编译效率
可以加上 cacheDirectory 参数或使用 transform-runtime 插件试试
- // webpack.config.JS
- use: [{
- loader: 'babel-loader',
- options: {
- cacheDirectory: true
- }]
- // .bablerc
- {
- "presets": [
- "env",
- "react"
- ],
- "plugins": ["transform-runtime"]
- }
不需要打包编译的插件库换成全局 "script" 标签引入的方式
比如 jQuery 插件, react, react-dom 等, 代码量是很多的, 打包起来可能会很耗时
可以直接用标签引入, 然后在 webpack 配置里使用 expose-loader 或 externals 或 ProvidePlugin 提供给模块内部使用相应的变量
- // @1
- use: [{
- loader: 'expose-loader',
- options: '$'
- }, {
- loader: 'expose-loader',
- options: 'jQuery'
- }]
- // @2
- externals: {
- jQuery: 'jQuery'
- },
- // @3
- new webpack.ProvidePlugin({
- $: 'jquery',
- jQuery: 'jquery',
- 'window.jQuery': 'jquery'
- }),
优化构建时的搜索路径
在 webpack 打包时, 会有各种各样的路径要去查询搜索, 我们可以加上一些配置, 让它搜索地更快
比如说, 方便改成绝对路径的模块路径就改一下, 以纯模块名来引入的可以加上一些目录路径
还可以善于用下 resolve alias 别名 这个字段来配置
还有 exclude 等的配置, 避免多余查找的文件, 比如使用 babel 别忘了剔除不需要遍历的
来源: http://www.jianshu.com/p/3b058a7a7c7f