参考:
- https://github.com/elecrabbit/front-end-interview/blob/master/docs/guide/webpack.md
- https://github.com/elecrabbit/front-end-interview/blob/master/docs/guide/engineering.md
- https://github.com/elecrabbit/front-end-interview/blob/master/docs/guide/ast.md
- https://github.com/elecrabbit/front-end-interview/blob/master/docs/guide/WebpackHMR.md
- https://github.com/elecrabbit/front-end-interview/blob/master/docs/guide/webpackPlugin.md
- https://github.com/elecrabbit/front-end-interview/blob/master/docs/guide/webpackPluginDesign.md
- https://github.com/elecrabbit/front-end-interview/blob/master/docs/guide/webpackMoudle.md
- https://github.com/elecrabbit/front-end-interview/blob/master/docs/guide/webpackLoader.md
- https://github.com/elecrabbit/front-end-interview/blob/master/docs/guide/babelPlugin.md
谈谈你对 webpack 的看法
webpack的主要原理是,它将所有的资源都看成是一个模块,并且把页面逻辑当作一个整体,通过一个给定的入口文件,webpack 从这个文件开始,找到所有的依赖文件,将各个依赖文件模块通过loader和plugins处理后,然后打包在一起,最后输出一个浏览器可识别的JS结果文件。
Webpack 具有四个核心的概念,分别是 Entry(入口)、Output(输出)、loader 和 Plugins(插件)。
- Entry:是 webpack 的入口起点,它指示 webpack 应该从哪个模块开始着手,来作为其构建内部依赖图的开始。
- Output:属性告诉 webpack 在哪里输出它所创建的打包文件,也可指定打包文件的名称,默认位置为 ./dist。
- loader:可以理解为 webpack 的编译器,它使得 webpack 可以处理一些非 JavaScript 文件。在对 loader 进行配置的时候,test 属性,标志有哪些后缀的文件应该被处理,是一个正则表达式。use 属性,指定 test 类型的文件应该使用哪个 loader 进行预处理。常用的 loader 有 css-loader、style-loader 等。
- Plugin:插件可以用于执行范围更广的任务,包括打包、优化、压缩、搭建服务器等等,要使用一个插件,一般是先使用 npm 包管理器进行安装,然后在配置文件中引入,最后将其实例化后传递给 plugins 数组属性。
js
// webpack.config.js
import path, { dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import HtmlWebpackPlugin from 'html-webpack-plugin'
export default {
entry: './src/index.js',
plugins: [
new HtmlWebpackPlugin({
title: 'Caching',
}),
],
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader']
},
{
test: /\.(png|svg|jpg|jpeg|gif)$/i,
type: 'asset/resource'
}
]
},
output: {
path: path.resolve(dirname(fileURLToPath(import.meta.url)), 'dist'),
filename: '[name]-bundle.js',
clean: true
},
optimization: {
runtimeChunk: 'single',
},
};
使用 webpack 的确能够提供我们对于项目的管理,但是它的缺点就是调试和配置起来太麻烦了。但现在 webpack4.0 的免配置一定程度上解决了这个问题。但是我感觉就是对我来说,就是一个黑盒,很多时候出现了问题,没有办法很好的定位。
webpack与grunt、gulp 的不同?
- Grunt、Gulp是基于任务运⾏的⼯具: 它们会⾃动执⾏指定的任务,就像流⽔线,把资源放上去然后通过不同插件进⾏加⼯,它们包含活跃的社区,丰富的插件,能⽅便的打造各种⼯作流。
- Webpack是基于模块化打包的⼯具: ⾃动化处理模块,webpack把⼀切当成模块,当 webpack 处理应⽤程序时,它会递归地构建⼀个依赖关系图 (dependency graph),其中包含应⽤程序需要的每个模块,然后将所有这些模块打包成⼀个或多个bundle。
因此这是完全不同的两类⼯具,⽽现在主流的⽅式是⽤npm script代替Grunt、Gulp,npm script同样可以打造任务流。
webpack、rollup、parcel 优劣?
- webpack适⽤于⼤型复杂的前端站点构建: webpack有强⼤的loader和插件⽣态,打包后的⽂件实际上就是⼀个⽴即执⾏函数,这个⽴即执⾏函数接收⼀个参数,这个参数是模块对象,键为各个模块的路径,值为模块内容。⽴即执⾏函数内部则处理模块之间的引⽤,执⾏模块等,这种情况更适合⽂件依赖复杂的应⽤开发。
- rollup适⽤于基础库的打包,如vue、d3等,Rollup就是将各个模块打包进⼀个⽂件中,并且通过Tree-shaking来删除⽆⽤的代码,可以最⼤程度上降低代码体积,但是rollup没有webpack如此多的的如代码分割、按需加载等⾼级功能,其更聚焦于库的打包,因此更适合库的开发。
- parcel适⽤于简单的实验性项⽬: 他可以满⾜低⻔槛的快速看到效果,但是⽣态差、报错信息不够全⾯都是他的硬伤,除了⼀些玩具项⽬或者实验项⽬不建议使⽤。
Loader 和 Plugin 的不同?
- Loader直译为"加载器",Webpack将⼀切⽂件视为模块,但是webpack原⽣是只能解析 js⽂件,如果想将其他⽂件也打包的话,就会⽤到loader, 所以Loader的作⽤是让webpack拥有了加载和解析⾮JavaScript⽂件的能⼒。
- Plugin直译为"插件",Plugin可以扩展webpack的功能,让webpack具有更多的灵活性。在Webpack运⾏的⽣命周期中会⼴播出许多事件,Plugin可以监听这些事件,在合适的时机通过Webpack 提供的API 改变输出结果。
bundle,chunk,module 是什么?
- bundle:是由webpack打包出来的⽂件;
- chunk:代码块,⼀个chunk由多个模块组合⽽成,⽤于代码的合并和分割;
- module:是开发中的单个模块,在webpack的世界,⼀切皆模块,⼀个模块对应⼀个⽂件,webpack会从配置的entry中递归开始找出所有依赖的模块。
有哪些常⻅的 Plugin?
- define-plugin:定义环境变量
- html-webpack-plugin:简化 html⽂件创建
- uglifyjs-webpack-plugin:通过 UglifyES 压缩ES6 代码
- webpack-parallel-uglify-plugin: 多核压缩,提⾼压缩速度
- webpack-bundle-analyzer: 可视化 webpack 输出⽂件的体积
- mini-css-extract-plugin: CSS 提取到单独的⽂件中,⽀持按需加载
有哪些常⻅的 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 代码
注意:在Webpack中,loader的执行顺序是从右向左执行的。因为webpack选择了compose这样的函数式编程方式,这种方式的表达式执行是从右向左的。
如何⽤webpack 来优化前端性能?
⽤webpack 优化前端性能是指优化 webpack 的输出结果,让打包的最终结果在浏览器运⾏快速⾼效。
- 压缩代码:删除多余的代码、注释、简化代码的写法等等⽅式。可以利⽤webpack的UglifyJsPlugin和ParallelUglifyPlugin来压缩JS⽂件,利⽤ cssnano(css-loader?minimize)来压缩css
- 利⽤CDN加速: 在构建过程中,将引⽤的静态资源路径修改为CDN上对应的路径。可以利⽤webpack对于output参数和各loader的publicPath参数来修改资源路径
- Tree Shaking: 将代码中永远不会⾛到的⽚段删除掉。可以通过在启动 webpack 时追加参数
--optimize-minimize来实现 - Code Splitting: 将代码按路由维度或者组件分块(chunk),这样做到按需加载,同时可以充分利⽤浏览器缓存
- 提取公共第三⽅库: SplitChunksPlugin插件来进⾏公共模块抽取,利⽤浏览器缓存可以⻓期缓存这些⽆需频繁变动的公共代码
Babel 的原理是什么?
babel的转译过程也分为三个阶段,这三步具体是:
- 解析Parse: 将代码解析⽣成抽象语法树(AST),即词法分析与语法分析的过程;
- 转换Transform: 对于 AST 进⾏变换⼀系列的操作,babel 接受得到 AST 并通过 babel-traverse 对其进⾏遍历,在此过程中进⾏添加、更新及移除等操作;
- ⽣成Generate: 将变换后的 AST 再转换为JS 代码, 使⽤到的模块是 babel-generator。
前端知识库