1、前端为什么要进行打包和构建
代码层面
-- 体积更小(Tree-shaking,压缩,合并),加载更快
-- 编译高级语言和语法(TS,ES6+,模块化,sass等)
-- 兼容性和错误检查(polyfill,postcss,eslint)
研发流程
-- 统一、高效的开发环境
-- 统一的构建流程和产出标准
-- 集成公司构建规范(提测、上线等)
2、module、chunk、bundle的区别
-- module各个源码文件,webpack中一切皆模块
-- chunk多模块合成的一个代码产出块,如entry、import()、splitChunk等
-- bundle最终产出的文件,每个chunk打包完都会产生一个bundle
3、loader和plugin的区别
-- loader模块转换器,单纯文件转换的过程,如less -》css
-- plugin就是个扩展插件,针对的是loader结束后,webpack打包的整个过程,它并不直接操作文件,而是基于事件机制工作,会监听ebpack打包过程中的某些节点,执行广泛的任务
4、常见的loader和plugin有哪些
loader:
-- babel-loader(语法转化)
-- style-loader、css-loader、postcss-loader、less-loader(样式处理的loader)
-- file-loader、url-loader(处理文件)(url-loader一般线上使用缓存等去优化构建)
-- thread-loader多进程构建
plugin:
-- HtmlWebpackPlugin(生成html模版)
-- MiniCssExtractPlugin(抽离公共css)
-- HappyPack多进程构建
-- parallelUglifyPlugin多进程压缩
-- HotModuleReplacementPlugin热跟新
-- DllPlugin分包
5、babel和webpack的区别
-- babel js新语法编译工具,不关心模块化
-- webpack 打包构建工具,是多个loader和plugin的集合
6、如何产出一个lib
output: {
// lib文件名
filename: 'lodash.js',
// 输出lib到dist目录下
path: disPath,
// lib的全局变量名
library: 'lodash'
}
7、babel-polypill和babel-runtime的区别
-- babel-polypill会污染全局,babel-runtime不会
-- 产出第三方lib要用babel-runtime
8、webpack如何实现懒加载
-- import()
-- 结合vue,react的异步组件
-- 结合vue-router,react-router异步加载路由
9、为何proxy不能被polyfill
-- class可以用function模拟
-- promise可以通过回调模拟
-- proxy无法用Object.defineProperty模拟
10、webpack性能优化方法
-- 使用高版本的webpack
-- 多线程/多实例构建:
happyPack(被后续版本弃用)、thread-loader
parallelUglifyPlugin多进程压缩js(不推荐使用,项目基本处于没人维护阶段)
-- 缩小打包作用域:
exclude/include(确定loader范围)
resolve.modules指明第三方模块的绝对路径(减少不必要的查找)
resolve.extensions尽可能减少后缀尝试的可能性
noParse对完全不需要解析的库进行忽略(不去解析但仍会打包到bundle中,注意被忽略的文件里面不应该包括import、require、define等语句)
IgnorePlugin(完全排除模块)
合理利用alias
-- 充分利用缓存提升二次构建速度
优化babel-loader
terser-webpack-plugin开启缓存
DllPlugin 动态链接库插件进行分包
11、webpack优化产出代码方法
-- 小图片base64位编码
-- bundle + hash
-- 懒加载
-- 提取公共代码
-- ignorePlugin
-- 使用cdn加速
-- 使用production(自动压缩代码和使用Tree-Shaking;注意:ES6 Module才能让tree-shaking生效;commonjs不行)
-- Scope Hosting
12、简述webpack的构建流程
Webpack 的运⾏流程是一个串⾏的过程,从启动到结束会依次执⾏以下流程 :
初始化参数:从配置⽂件和 Shell 语句中读取与合并参数,得出最终的参数
开始编译:⽤上一步得到的参数初始化 Compiler 对象,加载所有配置的插件,执⾏对象的 run ⽅法开始执⾏编译
确定⼊⼝:根据配置中的 entry 找出所有的⼊⼝⽂件
编译模块:从⼊⼝⽂件出发,调⽤所有配置的 Loader 对模块进⾏翻译,再找出该模块依赖的模块,再递归本步骤直到所有⼊⼝依赖的⽂件都经过了本步骤的处理
完成模块编译:在经过第 4 步使⽤ Loader 翻译完所有模块后,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系
输出资源:根据⼊⼝和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的⽂件加⼊到输出列表,这步是可以修改输出内容的最后机会
输出完成:在确定好输出内容后,根据配置确定输出的路径和⽂件名,把⽂件内容写⼊到⽂件系统
在以上过程中,Webpack 会在特定的时间点⼴播出特定的事件,插件在监听到感兴趣的事件后会执⾏特定的逻辑,并且插件可以调⽤ Webpack 提供的 API 改变Webpack 的运⾏结果
13、简述babel的编译过程
Babel 是⼀个 JavaScript 编译器,是⼀个⼯具链,主要⽤于将采⽤ ECMAScript 2015+ 语法编写的代码转换为向后兼容的 JavaScript 语法,以便能够运⾏在当前和旧版本的浏览器或其他环境中。
Babel 本质上就是在操作 AST 来完成代码的转译。AST是抽象语法树(Abstract Syntax Tree, AST)如果想要了解更多,可以阅读和尝试:
-- 分析 AST :ASTexplorer.net
-- AST 规范:github.com/estree/estr…
Babel 的功能很纯粹,它只是⼀个编译器。⼤多数编译器的⼯作过程可以分为三部分:
-- 解析(Parse) :将源代码转换成更加抽象的表示⽅法(例如抽象语法树)。包括词法分析和语法分析。词法分析主要把字符流源代码(Char Stream)转换成令牌流( Token Stream),语法分析主要是将令牌流转换成抽象语法树(Abstract Syntax Tree,AST)。
-- 转换(Transform) :通过 Babel 的插件能⼒,对(抽象语法树)做⼀些特殊处理,将⾼版本语法的 AST 转换成⽀持低版本语法的 AST。让它符合编译器的期望,当然在此过程中也可以对 AST 的 Node 节点进⾏优化操作,⽐如添加、更新以及移除节点等。
-- ⽣成(Generate) :将 AST 转换成字符串形式的低版本代码,同时也能创建 Source Map 映射。
经过这三个阶段,代码就被 Babel 转译成功了。