最近找工作整理了一些面试题,分享给大家一起来学习。如有问题,欢迎指正。
前端面试题系列文章:
webpack是什么
webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。
在项目中我们可能会用到.less文件和es6文件,我们需要将这些文件转换成html能直接使用的文件,比如less转css , es6转es5 。 我们可以先转换文件,再引用到html中,但这样做非常的繁琐,类似的文件数量一多,将会变成非常麻烦的事情。这时,我们可以使用webpack打包工具,将这些文件一次性打包并使用,简化打包的过程。
Webpack核心概念:
-
Entry
entry是配置模块的入口,作为构建其内部依赖图的开始。
-
Output
output输出的配置。 告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件,默认值为 ./dist。
基本上,整个应用程序结构,都会被编译到你指定的输出路径的文件夹中。
-
Module
模块,在 Webpack 里一切皆模块,一个模块对应着一个文件。Webpack 会从配置的 Entry 开始递归找出所有依赖的模块。
-
Chunk
代码块,一个 Chunk 由多个模块组合而成,用于代码合并与分割。
-
Loader
模块转换器,用于把模块原内容按照需求转换成新内容。
-
Plugin
plugin是一个扩展器,它丰富了webpack本身,针对是loader结束后,webpack打包的整个过程,它并不直接操作文件,而是基于事件机制工作,会监听webpack打包过程中的某些节点,执行广泛的任务。
在webpack运行的生命周期中会广播出许多事件,plugin可以监听这些事件,在合适的时机通过webpack提供的API改变输出结果
Webpack打包流程
- 读取
webpack
的配置参数; - 启动
webpack
,创建Compiler
对象并开始解析项目; - 从入口文件(
entry
)开始解析,并且找到其导入的依赖模块,对不同文件类型的依赖模块文件使用对应的Loader
进行编译 - 根据依赖模块递归遍历分析,得到了每个模块被翻译后的最终内容以及它们之间的依赖关系;
- 根据入口和模块之间的依赖关系,组装成一个个包含多个模块的 Chunk,再把每个 Chunk 转换成一个单独的文件加入到输出列表
- 整个过程中
webpack
会通过发布订阅模式,向外抛出一些hooks
,而webpack
的插件即可通过监听这些关键的事件节点,执行插件任务进而达到干预输出结果的目的。
webpack打包后的几种hash模式
-
hash
模式底层是创建生成一个新的
hash
实例,打包时,每个文件都同时写入同一个hash
值。而这种形式,相当于把所有代码资源都更新了,类似于全量更新
-
chunkhash
模式基于
hash
模式进行改进,当前文件改变时,当前文件所引入的依赖和当前文件的hash
值都会重新生成一个新的hash值
。而其他未改变的内容的文件,或者和它们无依赖关系的文件,保持原有的hash
值。未更新的文件可以进行缓存的作用,它可以说是一种局部更新
-
contenthash
模式contenthash
模式:contenthash
可以说是较好的一种hash
模式,它是在chunkhash
上再一次改良。当前文件的内容发生变化时,当前文件的hash
值才会重新生成。而涉及到的依赖的文件和其他文件没有改变内容的情况下,保持原有的hash值
。对long term cache
长期缓存很友好。这种行为类似于最小量更新
重新打包部署后浏览器缓存问题
应用部署后,为了防止客户端反复请求资源,服务器都会设置缓存,来减少带宽流量压力。
但是设置缓存之后就会出现问题,当我们进行打包部署之后,因为缓存问题,用户访问的还是未更新的页面,
每次打包生成和上一次不同的文件名,全新的文件名就代表全新的请求,自然不会有缓存问题。
解决方案: Nginx配置+打包文件后缀修改
Ngnix配置:
location = /index.html {
add_header Cache-Control "no-cache, no-store";
}
vue.config.js文件:(时间戳或者hash模式)
configureWebpack: { // webpack 配置
output: { // 输出重构 打包编译后的js文件名称,添加时间戳.
filename: `js/js[name].${timeStamp}.js`,
chunkFilename: `js/chunk.[id].${timeStamp}.js`
},
},
css: {
extract: { // 打包后css文件名称添加时间戳
filename: `css/[name].${timeStamp}.css`,
chunkFilename: `css/chunk.[id].${timeStamp}.css`
}
}
sourceMap
sourceMap
是一项将编译、打包、压缩后的代码映射回源代码的技术,由于打包压缩后的代码并没有阅读性可言,一旦在开发中报错或者遇到问题,直接在混淆代码中debug
问题会带来非常糟糕的体验,sourceMap
可以帮助我们快速定位到源代码的位置,提高我们的开发效率。
devtool: 'eval-source-map'
-
source-map
- 外部生成,在外部生成独立的同名.map 文件
- 可以提示
- 错误代码准确信息和源代码的错误位置。
- 错误位置信息可以精确到某行某列
-
inline-source-map
- 内联生成,既映射的内容在生成的 js 文件内部,不独立生成.map 文件
- 只生成一段内联 source-map 内容(集中生成)。
- 可以提示:错误代码准确信息和源代码的错误位置。
-
eval-source-map
- 同inline-source-map属于内联生成。
- 不同之处是在生成的 js 文件内部,每一个加载进来的 js 文件内容,都会有一段独立的 source-map 内容。
- 可以提示:错误代码准确信息和源代码的错误位置。
-
cheap-source-map
|cheap-module-source-map
- 外部生成,在外部生成独立的同名.map 文件。
- 可以提示:
- 错误代码准确信息和源代码的错误位置。
- 错误位置信息只精确到行,无法精确到列。
-
nosources-source-map
- 外部生成,在外部生成独立的同名.map 文件。
- 可以提示:
- 错误代码错误信息,但是没有任何源代码信息(源代码和构建后代码都没有)。
-
hidden-source-map
- 外部生成,在外部生成独立的同名.map 文件。
- 可以提示:
-
错误代码错误信息,但是没有错误位置。
-
不能追踪到源代码的错误位置,只能提示到构建后代码的错误位置。
-
开发环境:
-
速度快(eval>inline>cheap>...)
- 例如:
eval-cheap-souce-map
eval-source-map
- 例如:
-
调试更友好
- 例如:
souce-map
cheap-module-souce-map
cheap-souce-map
- 例如:
-
推荐选择
eval-source-map
或eval-cheap-module-souce-map
- VUE默认使用
eval-source-map
模式
生产环境
-
推荐选择
source-map
或cheap-module-souce-map
-
如要要考虑隐藏源代码
-
hidden-source-map
只隐藏源代码,会提示构建后代码错误信息 -
nosources-source-map
全部隐藏
-
常用的 Loader
- css-loader: 加载CSS文件(
@import
和url()
) - style-loader: 使用
<style>
将css文件样式注入到我们的HTML页面 - postcss-loader: 自动添加 CSS3 部分属性的浏览器前缀
- less-loader: 编译 less 转 css
- file-loader: 解析文件 url,并将图片 copy 到指定目录
- url-loader: 一般与 file-loader 搭配使用,如果文件小于限制的大小。则会返回 base64 编码,否则使用 file-loader 将文件移动到输出的目录中
- svg-sprite-loader
- babel-loader:将 ES6/7/8 语法转换为 ES5 语法,但是对新 api 并不会转换(promise、Generator、Set、Maps、Proxy 等),需要借助 babel-polyfill 来帮助我们转换
- vue-loader:用于解析.vue 文件
- vue-template-compiler:用于编译模板
- vue-style-loader:解析 vue 文件的样式
常用的 plugins
plugin | 作用 |
---|---|
html-webpack-plugin | webpack 打包出来的文件我们需要引入到 html |
clean-webpack-plugin | 打包输出前清空文件夹 |
webpack-bundle-analyzer | 生成代码分析报告,帮助提升代码质量和网站性能。 |
webpack优化
-
external:排除第三方包,使用cdn引入
externals
配置项用来告诉Webpack
要构建的代码中使用了哪些不用被打包的模块,也就是说这些模版是外部环境提供的,Webpack
在打包时可以忽略它们使用场景:用webpack构建的工程,当工程规模达到一定程度时,都有必要将
体积较大的
、基本无变动
的第三方包处理为externals
,以减小入口js文件的大小
,缩短首屏加载时长
;减小依赖包体积
index.html
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
vue.config.js
externals: { vue: 'Vue' }
-
分包splitchunks:文件过大,分包
-
什么是chunks: 对于打包产物bundle, 有些情况下,我们觉得太大了。 为了优化性能,我们需要对bundle进行以下拆分,对于拆分出来的东西叫chunk。
-
代码分割的三种方式
-
入口起点:使用
entry
配置手动地分离代码// `entry` 里配置多个入口即可: entry: { app: "./index.js", app1: "./index1.js" }
-
动态引入:通过模块的内联函数调用来分离代码。
//`import()` 加载的模块分离成独立的包: import("./a");
-
防止重复:使用
splitChunks
去重和分离 chunk。使用splitChunks
配置分离规则,然后webpack
自动将满足规则的chunk
分离。一切都是自动完成的。
-
-
optimization.splitChunks.chunks: async(默认) | initial | all
- async: 对于动态加载的模块,默认配置会将该模块单独打包。使用以下语法进行动态加载(还有其他写法):
import('lodash')
-
all: 使用默认配置进行分包(optimization.splitChunks的配置),所有类型的模块进行拆分;
-
initial:使用默认配置进行分包(optimization.splitChunks的配置),将动态引入和静态引入的同一模块分开处理(多个相同的chunk包)
只有当chunks 不为async时,webpack打包的默认配置才会是default配置
-
使用contentHash,对修改的内容文件部署进行更新
利用浏览器缓存,重新部署后,不会重新加载未更新的代码文件
configureWebpack: { output: { filename: `js/[name]_[contenthash].js`, chunkFilename: `js/[name]_[contenthash]js` }, }, css: { //重点. extract: { // 打包后css文件名称添加时间戳 filename: `css/[name]_[contenthash].css`, chunkFilename: `css/[name]_[contenthash].css` } },
Vite 和 webpack 的区别
- Vite构建速度快。Vite在开发模式下使用本地ES模块,不需要生成项目依赖,使用go构建,所以构建速度较快。Vite的插件生态相对较新。
- Webpack作为构建工具,使用node构建,速度较慢