工程化笔记¶
统计信息:字数 41532 阅读84分钟
原始笔记链接:https://cloud.seatable.cn/dtable/external-links/59b453a8639945478de2/
0020 npm 模块安装机制是什么?npm install 原理¶
这个就是依赖树的问题
1 读取 package.json 文件,解析出 dependencies 和 devDependencies 中全部的依赖文件,这是一个列表
2 循环数组,下载对应的依赖包,然后遍历依赖的依赖,如果没有下载,那么下载并放在数组中
3 直到数组中的依赖被全部下载完成
如果有两个库依赖的第三方库版本不一致,可能造成冲突,例如一个依赖 react16 另一个依赖 React18 这样就会报错。解决办法是 force 或者改成一样的依赖版本
0026 模块化的发展历程¶
早期的代码主要分为不同的模块,有AMD和cmd是两种,UMD是两种模块化语法的兼容。
nodejs中自带的模块化是common-js require
ES6当中新的语法主要是 esModules——import
0070 Webpack热更新的原理是什么¶
webpack-dev-server 开启一个内置的开发服务器
web-socket 实现双向通信
hmr 实现热更新
当代码变化后,webpack 重新编译打包,然后通知 socket 更新到界面上。HMR 实现热更新(局部更新)
HMR **(Hot Module Replacement)**的工作流程大致可以分为以下几个步骤:
-
建立WebSocket连接:应用程序在初始化时与Webpack Dev Server建立WebSocket连接,以便实时接收更新通知。
-
监听文件变化:当开发过程中的文件发生变化时,Webpack Dev Server会监听到这些变化,并通过WebSocket通知应用程序。
-
获取模块更新清单:接到通知后,HMR Runtime会发起HTTP请求,获取模块更新清单(manifest)。这个清单包含了所有需要更新的模块信息。
-
下载并应用更新:一旦获取到更新清单,HMR Runtime会下载每一个更新模块,并在所有新模块下载完成后,准备就绪并进入应用阶段。在这一阶段,所有失效的模块会被释放并从模块系统中卸载掉,最后更新模块的hash并调用所有相关的accept事件处理函数。
-
处理模块更新:Webpack运行时触发变更模块的module.hot.accept回调,执行代码变更逻辑。这允许开发者在运行时替换、添加或删除模块,而无需进行全页刷新。
0107 Mvc、MVP、mvvm 有什么区别¶
这些都是软件设计架构
MVC 架构¶
model view controller
View 是视图层,可以把数据显示在界面,用户直接和视图层交互;Controller 是控制器,主要处理界面的业务逻辑(打开关闭组件等)。Model 是数据层,主要存储底层数据(文件内容,表格信息)。
MVC通信是单向流:View 中用户交互会触发 Controller 控制器,Controller 处理用户输入改变 Model 数据层,数据层改变后会重新渲染 View 视图层。
用户可以与视图层交互,也可以通过URL等直接操作Controller(这是backbone的交互逻辑)
mvc: model-view-controller 数据层,视图层,控制层。当用户交互时间发生,view 监听事件,将事件传递到 model,model 处理后更新 view 层。同时 View 也可以直接更改 Model 层,类似下面的架构。
总体的设计模式(组件设计)低耦合高内聚,不同功能组件避免耦合。数据层和展现层的分离(例如使用 redux 的设计方案,view 层触发 action,更改对应的 store,重新计算后更新界面,这样就做到数据和视图的分离)。
MVC架构的好处:model 是数据层,View 是视图层,Controller 是控制层。
在实际项目中,model 是界面中实际的数据,例如上传的图片和行的信息。view 是界面中显示的按钮和控件,以及控制这些控件的 react 状态。Controller 是接口和API。如果一个引用做到 MVC 完全分离,然后不同模块完全分离,如果需要改动某个模块,或者界面样式,或者数据层,都不会影响其他的部分。
例如,我们想把界面中的按钮改成输入框,那么直接更改 View 层即可,不需要改动 Model 层。如果项目的耦合性很强,可能数据划分不是很清楚。
MVP 架构¶
Presenter 展现层,处理大部分的业务逻辑。View 视图层不会部署业务逻辑(根据Presenter被动渲染)。
View 和 Presenter 是双向通信,Presenter 和 Modal 是双向通信。View 和 Modal 不会直接通信。
MVVM 架构¶
将 MVP 架构中的 Presenter 改成 ViewModal。
特点:View 和 ModalView 双向绑定,View 更改后直接体现在 ModalView 中。
MVVM 就是 model view view-model 三个,架构比上面好一点。这个数据层和 view-model 层进行通信数据交流,ViewModel 和 View 实现自动数据绑定,这个减少了组件代码的耦合。
这个最早在安卓端使用较多,还需要看实际的代码,可能一个很好的设计模式,对后续的扩展比较友好。如果一个模块设计的不合适,后续扩展,耦合性很大,就会有很多问题。
原始链接:http://www.ruanyifeng.com/blog/2015/02/mvcmvp_mvvm.html
0109 Webpack有常用的哪些 plugin 和 loader¶
loader 主要用于处理不同格式的文件转换
- css-loader (style-loader, css-loader, less-loader, scss-loader) 处理不同的样式,并编译成 css 然后进行打包;file-loader(把小文件打包成JS中);loader 执行的顺序是从右向左,例如匹配到 .less 文件就是这样执行的 postcss-loader
- resolve-url-loader 解析url()的相对路径
- thread-loader 多线程执行,这个用于多核CPU加速打包活过程
- url-loader: 和file-loader一样,但返回base64 data当文件大小小于某个值时
- babel-loader 把 ES6 代码编译成 ES5 代码等
plugin 处理特殊的功能和需求
- uglyfyJS 丑化代码,压缩代码
- html-webpack-plugin 生成页面
- happypack 也是加快编译效率
- transform-runtime 按需加载 antd-mobile 也是看版本,5以上配置就变化了
- mini-css-extract-plugin
注意:不同版本下 webpack 的配置不一样(从最早的3到5)
详情参考:https://www.npmjs.com/package/webpack
0692 前端如何 debug¶
chrome://inspect/
https://zhuanlan.zhihu.com/p/24353060
https://zhuanlan.zhihu.com/p/401550174
谷歌浏览器自带的调试工具,功能繁多,注意版本不同,实际上每一个功能都可以写成一个单独的知识点
用的时候可以专门学
0125 git 命名规范¶
- commit 命名:每次commit,要标准和准确的描述做了什么,改了什么,删除了什么,新增了什么
- 分支命名:version/1.2.3(大版本分支),feature/login(新增特性分支简写feat)person/michael-an/bugfix-editor(个人分支)special/firefox-debug(特殊分支)前面是大类-后面是功能说明 hotfix(紧急修复分支)
- tag只能适用稳定的版本
0126 git 提交 PR 流程¶
s1:配置 用户名/邮箱/软件界面:
git config --global user.name 'xxx'
git config --global user.email "xxx"
右键-options-looks 设置git外观和显示
s2:记录开发过程
初始化仓库——工作区——暂存区——持久区
S3 远程服务器交互
远程代码库(码云,github)
设置:注册
重要:SSH公钥-不同电脑设置不同的key
生成公钥:在bash中生成ssh公钥(具体命令网站上有)生成一个方框图案。将bash中产生的代码复制到码云中。
github 秘钥和公钥产生在我的文档下面.ssh文件夹中。
S4 忽略文件
.gitignore 文件不生效原因:git 中已经包含的文件存在缓存,需要删除这部分本地缓存文件。bash 清空缓存后,可以正常忽略文件。
git rm -r --cached .
git add .
git commit -m 'update .gitignore'
0127 软件开发的几种方法¶
软件工程中开发的几种方式
名称 | 定义 | 优点 | 缺点 |
---|---|---|---|
BDD 行为驱动开发 | 确定功能后,直接编辑完成行为的代码 | 面向行为,项目整体的框架明确,MVC 层划分明确,适合大型项目,适合没有案例的项目(自上而下) | 可能代码有问题,没有对应的测试文件,后期需要补充测试,考虑边界情况等 |
TDD 测试驱动开发 | 确定功能,编写测试用例,完成只能实现测试的代码,完善程序 | 代码健壮性强,针对性强(例如leetcode刷题,或者lodash工具库函数),适合模块化开发代码(自下而上) | 代码完成后,项目整体框架规范可能不一致,没有从顶层处理数据结构。编写测试耗时长。 |
瀑布流开发 | 类似BDD,有明确的开发流程:用户调研-产品需求-设计草图-编写代码-测试-上线-反馈与后续维护 | 适合大团队的明确分工,确定所有功能是否需要再动手,避免过程中由于产品需求变动,造成的代码返工等。 | 自上而下的开发,可能后续到测试阶段才发现不足,需要前期大量的会议论证等,需要前期明确的文档和需求 |
敏捷开发 | 直接面对用户,用户提出什么需求,就直接开发(二八定律,先不管代码的细节和极少数用户的情况) | 小步快跑,产品开发较快;适应于自驱力较强的开发者,程序员可以根据用户需求或者自己的体验直接开发功能 | 对于自驱力不强的程序员,没有明确的需求,就很难规范化开发。如果团队成员较多,开发效率并没有那么高。 |
实际上,一个公司可能使用多种开发方法;不同的开发团队(国外开放的理念,国内严格的等级),不同的项目需求,不同的时间限制等等,会采用不同的开发方法。
某一个项目,或者某个开发阶段,也可能有不同的开发方法。
总之:BDD和TDD可以对比,瀑布流开发和敏捷开发可以对比。人多或者情况复杂,需要规范明确,严格定义需要做什么。人员较少,时间紧张,那就优先开发出可视化的结果。
https://www.zhihu.com/question/19645396
https://baike.baidu.com/item/%E6%95%8F%E6%8D%B7%E8%BD%AF%E4%BB%B6%E5%BC%80%E5%8F%91/7108658
0128 软件设计的冗余和性能分析¶
数据结构的冗余:设计某个字段时,考虑可能扩容,例如单选改成多选,那么就需要从字符串改成数组字符串。如果早期设计中,就设计数组,就不需要考虑兼容早期的代码了。这个还是看需求:如果需求确定,不经常更改,那么就可以考虑性能为主。如果需求经常变化,那么需要考虑冗余。
服务器和硬件层面的冗余:如果主服务器或者主磁盘在某个情况下跑满或者故障,那么需要另一套服务器(或者另一个程序)目前开发的应用还不需要考虑多个系统处理冗余(因为 dev 挂了就修复,内存满了就重启线上服务器,不需要考虑完全不挂的情况)实际上大厂还是需要考虑的,不能线上环境突然挂了然后重启。
0183 如何提⾼webpack的打包速度¶
(1)优化 Loader¶
对于 Loader 来说,影响打包效率首当其冲必属 Babel 了。因为 Babel 会将代码转为字符串生成 AST,然后对 AST 继续进行转变最后再生成新的代码,项目越大,转换代码越多,效率就越低。当然了,这是可以优化的。
首先我们**优化 Loader 的文件搜索范围**
module
exports
module
rules
// js 文件才使用 babel
test
/\.js$/
loader
'babel-loader'
// 只在 src 文件夹下查找
include
resolve
'src'
// 不会去查找的路径
exclude
/node_modules/
对于 Babel 来说,希望只作用在 JS 代码上的,然后 node_modules
中使用的代码都是编译过的,所以完全没有必要再去处理一遍。
当然这样做还不够,还可以将 Babel 编译过的文件**缓存**起来,下次只需要编译更改过的代码文件即可,这样可以大幅度加快打包时间
loader
'babel-loader?cacheDirectory=true'
(2)HappyPack¶
受限于 Node 是单线程运行的,所以 Webpack 在打包的过程中也是单线程的,特别是在执行 Loader 的时候,长时间编译的任务很多,这样就会导致等待的情况。
HappyPack 可以将 Loader 的同步执行转换为并行的,这样就能充分利用系统资源来加快打包效率了
module
loaders
test
/\.js$/
include
resolve
'src'
exclude
/node_modules/
// id 后面的内容对应下面
loader
'happypack/loader?id=happybabel'
plugins new HappyPack
id 'happybabel'
loaders
'babel-loader?cacheDirectory'
// 开启 4 个线程
threads 4
(3)DllPlugin¶
DllPlugin 可以将特定的类库提前打包然后引入。这种方式可以极大的减少打包类库的次数,只有当类库更新版本才有需要重新打包,并且也实现了将公共代码抽离成单独文件的优化方案。DllPlugin的使用方法如下:
// 单独配置在一个文件中
// webpack.dll.conf.js
const
require
'path'
const
require
'webpack'
module
exports
entry
// 想统一打包的类库
vendor
'react'
output
path
join
'dist'
filename
'[name].dll.js'
library
'[name]-[hash]'
plugins
new
DllPlugin
// name 必须和 output.library 一致
name
'[name]-[hash]'
// 该属性需要与 DllReferencePlugin 中一致
context
path
join
'dist'
'[name]-manifest.json'
然后需要执行这个配置文件生成依赖文件,接下来需要使用 DllReferencePlugin
将依赖文件引入项目中
// webpack.conf.js
module
exports
// ...省略其他配置
plugins
new
DllReferencePlugin
context
// manifest 就是之前打包出来的 json 文件
manifest
require
'./dist/vendor-manifest.json'
(4)代码压缩¶
在 Webpack3 中,一般使用 UglifyJS
来压缩代码,但是这个是单线程运行的,为了加快效率,可以使用 webpack-parallel-uglify-plugin
来并行运行 UglifyJS
,从而提高效率。
在 Webpack4 中,不需要以上这些操作了,只需要将 mode
设置为 production
就可以默认开启以上功能。代码压缩也是我们必做的性能优化方案,当然我们不止可以压缩 JS 代码,还可以压缩 HTML、CSS 代码,并且在压缩 JS 代码的过程中,我们还可以通过配置实现比如删除 console.log
这类代码的功能。
(5)其他¶
可以通过一些小的优化点来加快打包速度
resolve.extensions
:用来表明文件后缀列表,默认查找顺序是
['.js', '.json']
,如果你的导入文件没有添加后缀就会按照这个顺序查找文件。我们应该尽可能减少后缀列表长度,然后将出现频率高的后缀排在前面
resolve.alias
:可以通过别名的方式来映射一个路径,能让 Webpack 更快找到路径
module.noParse
:如果你确定一个文件下没有其他依赖,就可以使用该属性让 Webpack 不扫描该文件,这种方式对于大型的类库很有帮助
https://juejin.cn/post/7197061916904898616#heading-3
0204 webpack 中 dev 和 production 环境区别¶
在开发模式下,直接通过 import 可以导入 CSS 文件。 在生产环境下,会把相互的依赖关系分别打包,然后后端模板中需要插入对应的打包后的JS和CSS文件。这个本地开发测试不出来。
dev正常,build 后不正常的情况,可能是不同开发环境打包逻辑不一样。如果一个模块被引用多次(具体次数根据配置文件决定),那么可能被打包到common.js中,然后影响全局的样式
本地环境下面,只显示项目的CSS,可能在生产环境下,项目中的CSS可能和第三方库的CSS冲突(类名冲突)
0186 图片和多媒体存储优化¶
1、设计角度:合适的图片格式,jpg png 雪碧图,字体图标、css 取代图片
2、后端角度:压缩图片、图片缩略图(后端),点击后展开大图
3、前端 webpack 压缩 image-webpack-loader,图片懒加载,图片响应式加载(大屏大图片,小屏幕小图片)
4、网络角度:CDN
图像切片:超大图片几个G,可以切成几个小图片,然后分别进行加载,这个需要后端技术处理,用于 TIFF 等格式,遥感扫描图等
0221 polyfill 是什么?作用是?¶
polyfill 英文翻译:垫片;计算机中指的是"补丁"
为什么使用:老版本浏览器需要较早的语法才能使用(IE11不能使用Object.assign)所以需要通过 babel 把高级语法转换成低级语法。我们可以设置需要支持的浏览器版本(例如使用babel 转换到 es3 还是 ES5 版本)。早期的版本需要更多代码,如果不想兼容 ie 678 那么可以节省不少代码。
垫片(补丁)分类
@babel/preset-env
@babel/runtime
@babel/folyfill
@babel/transform-runtime
core-js
补丁使用方法:手动、半自动、全自动。
1、手动:根据需求,安装对应的第三方库 Object.assign = require('object-assign')
不利于维护。
2、半自动:根据 webpack 覆盖率:preset-env 根据预设的环境打补丁 https://github.com/browserslist/browserslist 在配置文件中设置 corejs 和 targets 版本,即可打包对应版本的代码。
3、自动:polyfill.io 这个库可以根据浏览器的 UA 自动判断不同版本的代码并处理 https://polyfill.io/v3/ chrome 会不处理,IE 会转换。
参考链接:https://zhuanlan.zhihu.com/p/71640183
0222 thread-loader 多进程多线程打包¶
webpack 编译打包时间较多,可以使用 thread-loader,可以减少 webpack 打包编译时间
https://github.com/webpack-contrib/thread-loader
先定量分析一下打包时间,在耗时较多的 loader 前,使用 thread-loader 处理,使用单独的进程进行打包
多CPU的情况下,可以节省时间(8核节省75%的时间)
如果只使用 babel 转换,不使用 webpack 打包,那么影响不大
{
test: /\.(js|mjs)$/,
exclude: /@babel(?:\/|\\{1,2})runtime/,
use: [
{
loader: 'thread-loader',
},
{
loader: require.resolve('babel-loader'),
options: {
babelrc: false,
configFile: false,
compact: false,
cacheDirectory: true,
cacheCompression: false,
},
}
],
}
0345 前端加密算法有哪些?¶
为什么进行前端加密¶
在 http 协议下,数据是明文传输,传输过程中网络嗅探,可直接获取其中的数据,如用户的密码和信用卡相关的资料,一旦被中间人获取,会给用户带来极大的安全隐患。另一方面在非加密的传输过程中,攻击者可更改数据或插入恶意的代码等。
前端加密的意义: 即在数据发送前将数据进行哈希或使用公钥加密。如果数据被中间人获取,拿到的则不再是明文。
当然还有其他一些优点,例如避免后端等打印日志直接暴露明文密码,还可以避免明文撞库等。
加密方法¶
- 常见对称加密有AES、DES、3DES等,常用AES实现。
- 常见非对称加密有RSA、ECC等,常用RSA实现(公钥私钥,例如 github 登录)。
案例¶
crypto-js 实现前端对称加密,后端收到消息后解密。
md5
sha256
数据库加密¶
数据库存储用户名的密码时,加盐操作
参考链接¶
https://zhuanlan.zhihu.com/p/480875682
https://blog.csdn.net/w418856/article/details/130964706
0351 rollup 是什么?¶
为什么 rollup 打包赘余代码比较少?
rollup 是个打包的库
解答:官方介绍:https://rollupjs.org/
1、支持打包成不同格式:cmd, umd, cjs 等,按照需要打包
2、支持摇树,可以把不在依赖树的节点去掉,避免打包多余代码
3、支持文件拆分,根据不同节点进行动态拆分
4、其他插件(支持复杂功能)
0375 你知道哪些项目架构¶
有多种用于构建 React 项目的架构解决方案和模式。一些受欢迎的包括:
- MVC(模型-视图-控制器) :MVC 是一种传统的架构模式,它将应用程序分为三个主要组件 - 模型、视图和控制器。React 可以在 View 层中使用来渲染 UI,而其他库或框架可以用于 Model 和 Controller 层。
- Flux:Flux是Facebook专门针对React应用程序推出的应用程序架构。它遵循单向数据流,其中数据沿单个方向流动,从而更容易理解和调试应用程序的状态更改。
- 原子设计:原子设计并不是 React 特有的,而是一种将 UI 划分为更小、可重用组件的设计方法。它鼓励构建小型、独立且可以组合以创建更复杂的 UI 的组件。
- 容器和组件模式:该模式将表示(组件)与逻辑和状态管理(容器)分开。组件负责渲染 UI,而容器则处理业务逻辑和状态管理。
- 功能切片设计:它是一种用于组织和构建 React 应用程序的现代架构方法。它旨在通过根据功能或模块划分应用程序代码库来解决可扩展性、可维护性和可重用性的挑战。
0376 什么是特征切片设计¶
它是一种用于组织和构建 React 应用程序的现代架构方法。它根据功能或模块,划分应用程序代码库,来解决可扩展性、可维护性和可重用性的挑战。
在功能切片设计中,应用程序的每个功能或模块,都组织到一个单独的目录中,其中包含所有必要的组件、操作、reducers 和其他相关文件。
这有助于保持代码库的模块化和隔离性,使其更易于开发、测试和维护。
功能切片设计促进了关注点的清晰分离,并将功能封装在各个功能中。
这允许不同的团队或开发人员独立地处理不同的功能,而不必担心冲突或依赖性。
0356 项目负责人的写法¶
一份优秀的简历,学历和经验达标的情况下。
最首要是项目经历,这也是后续面试官和你聊的主要内容。
其次是影响力,比如个人博客,比如开源社区贡献,比如自己的文章。
然后是个人技能,列名词沾边就行。
简历A¶
角色:项目负责人
带领xxx人。
在xxx系统完成xxx模块,xxx模块,等10个模块。
实现xxx,xxx,xxx等上百个页面。
实现图形编辑器,音频波形图,xxx表格,等50个组件。
覆盖pc、安卓、小程序三端。
运用vue,vue-router,ts等等技术。
按ddd和solid分层、模块化插件化。
有脚手架、开发模板、代码lint、自动化测试、cicd、灰度、监控告警等工程化。
也有devops,低代码,版本控制等基建。
还有一些复杂状态管理,数据转化管理等等。
输出xx文章,框架。
提高xx产出
github xxx项目 300star
个人博客 xxx
简历B¶
角色:项目负责人
带队:xxx人
系统规模:
1,10个模块50个组件100个页面
2,覆盖pc、安卓、小程序三端。
系统亮点:
1,架构整洁:满足solid原则,分层模块化+容器化+插件化架构。
2,工程化完备:脚手架、开发模板、代码lint、自动化测试、cicd、灰度、监控告警等
3,基建完备:devops,低代码系统,版本控制平台,监控平台等等
4,复杂功能:图形编辑器,音频波形图,分层状态机,多模式匹配渲染,数据桥接器,复杂联动表格表单组件等。
成果:
1,团队战斗力提高:输出n篇课程文章,为公司提供xxx框架,提升xxx效率,减少xxxbug。
2,系统品质提升:故障降低xxx,性能提升xxx,用户满意度提升xxx。
3,团队产出提升:用户量同比提升xxx,节约xxx成本。
4,优化产研sop:提高xxx效率。
简历C(不好)¶
角色:项目开发
xxx系统
根据设计规范实现UI。
跟后端协商接口。
使用vue-router实现路由。
使用vuex管理状态。
实现一个复杂表单。
0260 团队中不同项目,如何避免干扰¶
团队中的问题以及解决方法
一个子项目中,不同子项目互相干扰,冲突的解决办法
- 代码规范统一:制定统一的规范(接口规范,UI规范,commit 规范等)
- UI 的统一:不同的子项目使用不同的前缀(CSS,公共组件)
- 编程能力统一:不同的同事水平不一样,那么按照中等的水平作为整体的标准(react hook typescript 等技术,根据团队技术水平决定)项目设置成不同的模块,不同人完成不同的模块,只要求接口统一
- 增加自动监测模块(单元测试,集成测试)整体项目的水平的保证
0261 如何重构代码和组件¶
为什么要重构?
原因:一个组件功能低耦合高内聚。历史原因,如果一个组件功能繁杂,逻辑比较乱,代码量很大,不便于管理,那么应该进行重构。
重构步骤:
1、理解功能:把当前组件的代码读懂,并理清不同的功能和界面匹配
2、划分重构边界:根据功能确定划分的部分(功能分类,还是界面分类),然后把不同的核心代码分开
3、迁移核心代码到不同子组件,优先调试小组件,并测试核心代码和传参正确性(import部分直接全部复制)
4、迁移类型检验,删除无用代码
5、重新整理类名,函数名等;微调内部结构。
6、最后判断预期效果是否达成。如果没有达到预期效果,或者重构后仍然有问题,需要重新开始前面步骤。
具体思考
1、项目开始前,就应该约定各种组件的规范,后期更改很麻烦,还可能有未知的错误和问题
2、自己写公共组件一定注意细节,这里需要多看官方组件的源代码,看看别人怎么写的。
为什么要写自己的组件?能不能使用传参优化已有的组件,避免造轮子是最好的,也要有造轮子的能力
0266 鲁棒性是什么¶
鲁棒性 Robust 健壮性
代码或者服务在不良环境下的稳定性,如果某个上下游服务延迟,或者高并发,是否有配套方案解决这个问题?例如支付宝接口的响应时间延迟,表现在线上就是淘宝支付的商品未付款。如果判断网络情况不好,需要自动降级或者友好提示。
或者用户输入的不符合规范,或者网络情况较差等,代码能否满足基本功能
0299 eslint-webpack-plugin 自动修复代码警告¶
作用:可以在编译时自动处理代码的 eslint 警告
环境:需要在 webpack 5 以上 + eslint 7 以上
npm install eslint-webpack-plugin --save-dev
然后在 webpack plugins 数组中增加这个插件和配置
const ESLintPlugin = require('eslint-webpack-plugin');
module.exports = {
plugins: [
new ESLintPlugin({
// 支持文件扩展名
extensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'],
// eslint 格式和路径
formatter: require.resolve('react-dev-utils/eslintFormatter'),
eslintPath: require.resolve('eslint'),
// 任何错误都会导致模块构建(module build)失败,默认值 true
failOnError: !(isEnvDevelopment && emitErrorsAsWarnings),
// 指定文件根目录,string
context: paths.appSrc,
// 后面的配置官方文档没有
cache: true,
cacheLocation: path.resolve(
paths.appNodeModules,
'.cache/.eslintcache'
),
cwd: paths.appPath,
resolvePluginsRelativeTo: __dirname,
baseConfig: {
extends: [require.resolve('eslint-config-react-app/base')],
rules: {
...(!hasJsxRuntime && {
'react/react-in-jsx-scope': 'error',
}),
},
},
}),
],
};
其他参考文档:https://webpack.docschina.org/plugins/eslint-webpack-plugin/
0300 npm 配置代理服务¶
# 先查看本机代理的端口号(对应的代理):7890
export https_proxy=http://127.0.0.1:7890
http_proxy=http://127.0.0.1:7890
all_proxy=socks5://127.0.0.1:7890
# 配置 npm 代理
npm config set proxy http://127.0.0.1:7890
npm config set https_proxy http://127.0.0.1:7890
npm config delete proxy
npm config delete https_proxy
0315 webpack 基本概念?常用插件和 loader?¶
下面是常用概念和个人理解:
entry: 入口文件,支持单入口(字符串)和多入口(对象)
output:输入文件(filename, path)
loaders: 不同格式的文件(正则匹配),优先使用 loader 进行转码,例如 sass less 转换成 css,SVG 转换成 file。这里执行的顺序是从后向前的,例如
{
test: /\.less$/,
use: [
{ loader: 'style-loader' },
{ loader: 'css-loader' },
{ loader: 'less-loader' },
],
exclude: /node_modules/
}
plugins: 插件,统一处理压缩打包过程(是否丑化,是否多线程执行,是否分析模块大小),常用插件如下
ExtractTextWebpackPlugin: 它会将入口中引用css文件,都打包都独立的css文件中,而不是内嵌在js打包文件中。
HtmlWebpackPlugin: 依据一个简单的index.html模版,生成一个自动引用你打包后的js文件的新index.html
HotModuleReplacementPlugin: 它允许你在修改组件代码时,自动刷新实时预览修改后的结果注意永远不要在生产环境中使用HMR。
OccurenceOrderPlugin: 为组件分配ID,通过这个插件webpack可以分析和优先考虑使用最多 的模块,然后为他们分配最小的ID
UglifyJsPlugin: 压缩代码
bundle:包,打包后的包
module:模块,原始模块化的多个模块
0325 peerDependencies 是什么?怎么使用?¶
我们进行项目开发时,通常会依赖很多第三方库,这些第三方会进一步依赖很多第三方库,由于依赖不同,最终依赖的底层的库的版本不同,造成打包后体积很大。
App
├── react@17.0.2
└─┬ nass-design@0.0.1
└── react@17.0.2
解决:在内层项目中,使用 PeerDependencies 处理某些公共的组件库,例如 react react-dom webpack 然后写一个通用的版本,然后在 devDependencies 中也安装公共的组件库。此时 npm publish 就不会把这部分依赖打包。
同版本依赖
"peerDependencies": {
"react": "^17.0.0"
}
然后外层项目执行 npm install 后,就会进行如下安装,避免了重复的底层库安装
App
├── react@17.0.2
└── nass-design@0.0.1
参考:
https://nodejs.org/en/blog/npm/peer-dependencies/
https://juejin.cn/post/7005890056640528421
https://blog.csdn.net/yinxiangzhongqing/article/details/132104847
https://blog.csdn.net/zhangchao19890805/article/details/78988364
版本号管理:如果修复 bug 那么只改动最后一位小版本;如果发布新功能,那么改动中间版本;如果发布大型跨越式改动,再改动第一个版本号。
0389 内容安全策略是什么¶
内容安全策略(Content-Security-Policy)是一种安全机制,用于保护 Web 应用程序免受特定类型的攻击,如跨站脚本攻击(XSS)和数据注入攻击。CSP 通过定义策略规则,控制浏览器允许加载和执行的资源,从而减少恶意代码的执行和数据泄漏的风险。
某些服务器在CSP(Content-Security-Policy)中设置了img-src 规则,访问外部的图片受阻。
如果没有设置CSP,可以直接访问这些外部的图片。
这里设置的意思是:只能加载下面的图片
-
与当前页面相同来源(
'self'
)。 -
数据 URL(
data:
)。 -
域名
mt0.google.com
、maps.googleapis.com
和maps.gstatic.com(可能是谷歌地图相关功能)
实际场景中遇到一次这个问题
0399 webpack-bundle-analyzer¶
统计第三方依赖占用的存储大小
https://github.com/webpack-contrib/webpack-bundle-analyzer
This module will help you:
-
Realize what's really inside your bundle
-
Find out what modules make up the most of its size
-
Find modules that got there by mistake
-
Optimize it!
0423 vite 如何获取环境变量¶
vite 官方给定的环境变量¶
可以在 JS 中使用全局变量
import.meta.env
可以在不同的开发环境下,使用不同的逻辑:
const basename = import.meta.env.MODE === 'production' ? 'path1' : 'path2';
-
import.meta.env.MODE: 当前构建模式,可以是"development"、"production"或"test"之一。
-
import.meta.env.BASE_URL: 当前项目的基准URL。
-
import.meta.env.PROD: 一个布尔值,表示当前是否处于生产模式。
-
import.meta.env.DEV: 一个布尔值,表示当前是否处于开发模式。
其他参考:https://blog.csdn.net/jieyucx/article/details/131503612
获取非 vite 官方环境变量的方法(第三方库 dotenv 实现)把配置放在 .env 文件中,这个库可以读出配置
https://www.npmjs.com/package/dotenv
通过这个也能说明,vite 并不是和 vue 深度绑定的,vite 就是一个工具也可以和 React 等很好的结合。
0447 服务器跨域问题¶
问题:本地开发时,网络请求错误,提示跨域错误。可能有下面几个情况:
情况1 某个服务器没有启动,请求显示跨域¶
解决过程:浏览器错误是跨域,服务器日志中显示编译错误
原因:因为在宿主机环境执行 npm install,服务在 docker 内部运行,某些第三方依赖库使用C语言编译,没有编译到 docker 内部(即使安装其他第三方库,也会影响已有的这个特殊的库)。所以造成 server 无法编译,服务不正常。nginx 反向代理服务器已经处理了跨域,但是已有服务没起来,所以界面显示的是跨域(找不到对应的服务)。
解决:在 docker 内部,删除 node_modules,重新 npm install 开启服务,正常使用。
总结:界面的报错不一定是真实的原因,需要查看日志,nginx 需要多了解。
情况2 后端处理跨域¶
使用 nginx 设置代理转发 proxy_pass,后端服务器开启在 7000,前端 webpack-dev-server 开启在 8080,然后统一转发到 22222 端口,这样就避免跨域了。
注:实际项目中,nginx 配置跨域后,node server 是上游服务器,upstream_server,也需要配置跨域。
server {
listen 22222;
server_name localhost;
location / {
add_header Access-Control-Allow-Origin 'http://localhost:8080' always;
add_header Access-Control-Allow-Headers '*';
add_header Access-Control-Allow-Methods '*';
add_header Access-Control-Allow-Credentials 'true';
if ($request_method = 'OPTIONS') {
return 204;
}
proxy_pass http://localhost:7000;
}
}
参考:https://blog.csdn.net/weixin_36380516/article/details/130960035
情况3:前端处理跨域¶
本地浏览器支持跨域操作(后端服务和前端页面不在一个端口,但是需要请求登录):更改本地浏览器配置。可以设置 webpack 支持代理,但是设置后无效,可能和 webpack 版本有关,所以直接使用命令行打开浏览器(增加参数打开)
参考:https://blog.csdn.net/qq_41541368/article/details/104035074
把浏览器的同源策略关掉,然后进行调试
open -n /Applications/Google\ Chrome.app/ --args --disable-web-security --user-data-dir=/Users/michael/workroom/chrome-config
0448 本地多个前端项目联调问题¶
如果本地多个前端项目需要联调(不同包之间互相引用),目前使用两种方法
1、手动复制依赖包文件
如果本地调试两个前端项目,一个项目需要使用另一个项目打包后的文件,可以直接写一个脚本,然后复制这个打包后的文件到另一个文件夹下面(npm link 也可以实现,但是可能存在缓存问题等等),所以写了这个联调脚本。
本地联调测试脚本
"move": "npm run prepublishOnly && mv -f /dtable/es /Users/xxx/workroom/dev/web/frontend/node_modules/@michael/dtable",
2、发布测试版本
可以直接发布 npm publish 一个测试版本,然后其他项目使用测试版本即可
0484 主流的前端打包工具有哪些?¶
常用几个打包库对比
名称 | stars | 周下载量 | 链接 |
---|---|---|---|
parcel | 43K | 20万 | https://parceljs.org/ |
rollup | 25K | 2241万 | https://www.npmjs.com/package/rollup |
webpack | 64K | 2641万 | https://www.npmjs.com/package/webpack |
rspack | 8k | 8w | https://github.com/web-infra-dev/rspack |
webpack¶
广泛使用,适合各种大型小型项目,各种插件很丰富。
rollup¶
适合小项目或者工具库,打包速度很快
parcel¶
很热,但是下载量一般,配置简单
rspack¶
字节内部推出的一个打包库,目前内部使用,外部应用不多
总之¶
一般情况使用 webpack。要求性能好打包快,配置简单,小型工具库,使用 rollup。
0661 常用 webpack 插件¶
这里常用插件,看一下是否过期
https://juejin.cn/post/6944940506862485511
https://juejin.cn/post/6844904193589772301
https://juejin.cn/post/6844903700226375687
一共30个插件,有的是 2018年使用,注意版本匹配,需要2小时以上
0693 早期 typora 免费使用方法¶
typora 是一个很好的 markdown 本地编辑器,使用如下