笔记打算记录,自己整理好的面试题,
争取保持准确性和专业性,然后用直白的语言描述出来,
希望能做成一个API文档,让我日后翻到能直接对着复习就好,
如果也能帮助到你就最好了(我会不定时的更新的)
babel 如何将 ES6(更新版本) 转换为 ES5
总共分为三个步骤(Babel 7 以后,插件都进行了命名规范调整,均以
@babel/作为开头)
- parser解析:
将代码逐字进行解析,打散后组装成对象(AST树:abstract syntax tree),babel 7以前使用的是 babylon插件,新版本改名为 @babel/parser
- transformer转换:
根据config.json中配置的plugins, preset,转换成新的AST树。使用babel-traverse插件(新版本 @babel/traverse)遍历AST树,通过babel-transform插件进行转换。(后续版本 transform插件合并到 @babel/core 中)
- generator:
将AST树转换成可以识别的ES5语法代码,使用babel-generator插件完成。
git / svn 的区别
svn
- 集中式管理(如果代码服务器有问题,则无法正常提交)
- 分支是复制整个文件夹目录(分支变化会影响到全局)
git
- 去中心化,分布式的管理
- 支持单独的代码分支
ESM / CJS 的理解
ESM
- 通过
import、export来进行导入和导出 ESM模块是异步加载的- 只有实际被使用的代码才会加载,其他导出的资源如果未被使用会被过滤掉
- 处于严格模式,防止混乱的全局变量
- 必要时,只能以
export default的形式引入CJS模块,否则会报错
//导出的多种方式
//1. 具体的命名导出 a.js
export const a = 'Value 1';
export const b = 'Value 2';
export function c() {
return 'Value 3'
}
//2. 默认导出 b.js (一个文件中只允许有一个 default 认导出)
export default function d() {
return 'abc'
}
//3. 支持混合导出 c.js
export default function e() {
return 'abc'
}
export const f = 'abc';
//对应的导入方式
//1.默认导入
//2.具体命名导入
//3.重命名导入(关键字:as)
//4.通配符全部导入(关键字:*)
CJS
- 通过
module.exports和require(资源路径)进行导出和导入操作 CJS模块是同步加载的,(异步加载的模块、模块的依赖关系)是需要项目运行后才能确定node环境默认支持CJS模块- 无法直接引入
ESM模块
//导出的方式
//1. 直接使用 module.exports ,可以直接将一个值(函数、对象、类等)赋值给 module.exports
const func = () => {
return 'abc'
}
module.exports = func;
//2. 使用 exports
exports.a = 'a';
exports.b = 'b';
exports.c = 'c';
//3. 使用 module.exports 进行对象赋值操作
module.exports = {
name: 'abc',
func: () => {
return 'aa'
}
}
//同一个js文件中,不建议同时使用 exports 和 module.exports
//同时使用的话,exports 导出的变量会全部失效
| ESM | CJS | |
|---|---|---|
| 资源加载 | 异步加载(可结合promise链式使用,更适合移动端) | 同步加载(更适合服务端,会出现阻塞) |
| 动态导入 | 支持运行时使用import()动态导入 | 没有API方法支持 |
| 静态分析 | 项目未编译(静态),可直接获取资源的依赖关系 | 需要项目编译运行后,才能计算出关系 |
| 全局变量 | 无 | 提供__dirname、__filename |
| 资源导入形式 | 导入的资源是使用引用的模式 | 导入的资源是使用引用的模式 |
| 模式 | 严格模式,无this关键字 | this指向当前模块 |
tree shaking 的理解
tree shaking是一种代码优化的概念,通过分析,剔除未被引用的
ES Module导出值,从而减少打包文件的体积,提升应用性能
tree shaking(依赖 ES Module的模块特性),只分析函数和 import、export 变量,tree shaking原理:
- 分析静态文件代码,整理出代码
import、export的依赖关系表 - 标记未使用的代码模块
- 去除无用代码,重新生成输出文件(实现代码瘦身)
- webpack中,当在生产模式
mode: 'production'的时候,会自动开启。如果需要更 准确 的 tree-shaking,还可以通过配置sideEffects字段,告诉工程哪些模块是不能够被剔除的。
{
// 当前的 style.css文件,不能被 tree-shaking,剔除掉
"sideEffects": ["./src/styles.css"]
}
rollup / webpack / vite 的理解
vite
- 先启动不做全量打包,再按需加载依赖文件,利用浏览器
ESM加载原理(加载 ESM 模块是通过 http 请求发送到浏览器),使用middleware插件对模块进行拦截,转换的过程使用esbuild(go语言)执行 - vite 当前版本使用
rollup配合打包
优点:
- 因为 unbundle(不预先全局构建)的机制,资源文件利用 http 缓存,使得 vite 有快速响应。
- 使用
esbuild(go语言)进行转换,go语言 比 nodejs 处理速度要快
缺点:
- unbundle 的机制 导致首屏、懒加载解析的时间变长。
webpack
- 结合
loader➕plugin,拥有更加全面的功能 - 启动服务后,会对工程进行预打包,分析依赖关系,然后再进行页面呈现
缺点:
- 构建后的代码,进行了tree shaking的代码瘦身,但是代码中会有部分预设的代码在里面(cjs转换成ESM的工程函数),所以整体没有
rollup打包后的精简
rollup
- 利用 tree shaking 的机制,将各模块进行打包,构建后的代码比
webpack要更精简 - 更专注于构建打包,没有按需加载,没有HMR功能
webpack 常见的减小体积的方法
- 利用插件
webpack-bundle-analyzer进行分析,查看哪些模块占用了最多的空间,从而做针对性的优化。
// webpack 会自动打开一个可视化界面展示
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
module.exports = {
plugins: [new BundleAnalyzerPlugin()],
};
- 利用插件动态加载css文件、剔除未使用的css文件(从而减小资源文件的体积)
// 动态加载
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
// 移除未使用的css
const PurgeCSSPlugin = require('purgecss-webpack-plugin');
- 代码压缩(针对 js代码、css代码、html代码)
- js代码:
terser-webpack-plugin - css代码:
css-minimizer-webpack-plugin - html:
html-webpack-plugin
// TerserWebpackPlugin (webpack 自带的工具,压缩 JS代码,移除注释,去掉 console.log)
module.exports = {
mode: 'production' // 自动使用 TerserWebpackPlugin 进行压缩
};
// 对比与传统的 UglifyJS, terser支持更新 ①更新版本的js代码、②配置更多、③多线程压缩
// css代码的压缩
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
// html代码(利用 html-webpack-plugin 搭配内建 minify 选项)
const HtmlWebpackPlugin = require('html-webpack-plugin');
- 引用第三方的库:例如用
lodash-es代替lodash,(更好配合 tree-shaking,从而减小文件大小) - 对静态文件进行优化:
- 例如使用插件压缩图片大小
image-webpack-loader, - 手动压缩图片资源大小
tinypng
- 例如使用插件压缩图片大小
webpack 常见的构建加速方法
-
使用缓存
cache,新版本 webpack支持文件缓存 -
启用多线程构建
// 使用 thread-loader 插件
module.exports = {
module: {
rules: [
{
test: /\.js$/,
use: ['thread-loader', 'babel-loader'],
exclude: /node_modules/
}
]
}
};
- 配置更优的
include和exclude(只处理需要构建的文件,例如src)
{
test: /\.js$/,
loader: 'babel-loader',
include: path.resolve(__dirname, 'src'),
exclude: /node_modules/
}
-
利用
CDN,(将第三方库使用 cdn 进入) -
减少过多的
alias配置,从而减少查找时间 -
使用
source-map时,选择更轻便的类型配合开发调试 -
可选择
esbuild替代babel进行构建,(因为go语言比js语言构建速度快)
gzip 压缩的理解
gzip 是一种压缩技术(算法),不是 Webpack 的插件,可以通过插件在构建阶段生成
.gz文件
- 在前端,gzip 压缩常用于服务器端,在将静态资源(如 JS、CSS、HTML)发送给浏览器之前进行压缩,以减小网络传输的体积,加快加载速度。
- 浏览器能自动识别
.gz文件并解压显示页面,不需要你手动干预
npm插件发布理解
项目工程中
package.json文件最关键
npm工程部署指令
npm version patch:1.0.0 升级为 1.0.1npm version minor:1.0.0 升级为 1.1.0npm version major:1.0.0 升级为 2.0.0
npm / yarn / pnpm 的理解
3个依赖库安装工具,都能够对用于管理工程项目中的package,但是也有存在一些不足的地方
npm:
- 安装 package时,以串行的形式下载,安装的时间较长
- 每一个工程项目都会重新单独下载所需的 package,会导致开发的文件夹容量较大,和系统频繁 I/O
- 当依赖库有自己的依赖时,会因为文件夹嵌套过深,导致在 Windows 无法正常访问的问题
- 因为 ③ 衍生出,A依赖库自己的依赖是 1.0版本的Z,B依赖库自己依赖的是 2.0版本的Z,导致
node_modules中出现依赖版本不一致的问题。
yarn:
在 npm 的基础上,优化了以下几个点:(仍保留了每个工程项目依赖库都会重新单独安装)
- 支持并行下载、离线缓存安装依赖库
- 支持依赖库
package-lock.json的概念(npm5.0 开始支持) - 引入依赖库扁平化的概念
依赖库扁平化带来的问题:
- 扁平算法复杂、耗时
- 扁平化后会出现未写入
package.json的依赖库,也能被使用。(工程只引入了A依赖库,A依赖库自己依赖B,工程直接使用 B依赖库,虽然会报错,但是能正常使用) - 多个不同的依赖库,各自所依赖的新依赖库版本不同时,扁平算法后会有不可预估的问题(文件路径有误、重复安装等)
pnpm:
名字是 performance npm,解决了npm、yarn重复安装,幽灵依赖的问题
- 一个工程项目中统一管理依赖库,安装后使用指针引用依赖库(减少 I/O,减少磁盘空间)