Skip to content

工程化笔记

统计信息:字数 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)​**的工作流程大致可以分为以下几个步骤:

  1. 建立WebSocket连接:应用程序在初始化时与Webpack Dev Server建立WebSocket连接,以便实时接收更新通知。

  2. 监听文件变化:当开发过程中的文件发生变化时,Webpack Dev Server会监听到这些变化,并通过WebSocket通知应用程序。

  3. 获取模块更新清单:接到通知后,HMR Runtime会发起HTTP请求,获取模块更新清单(manifest)。这个清单包含了所有需要更新的模块信息。

  4. 下载并应用更新:一旦获取到更新清单,HMR Runtime会下载每一个更新模块,并在所有新模块下载完成后,准备就绪并进入应用阶段。在这一阶段,所有失效的模块会被释放并从模块系统中卸载掉,最后更新模块的hash并调用所有相关的accept事件处理函数。

  5. 处理模块更新: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 层,类似下面的架构。

undefined

总体的设计模式(组件设计)低耦合高内聚,不同功能组件避免耦合。数据层和展现层的分离(例如使用 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 团队中不同项目,如何避免干扰

团队中的问题以及解决方法

一个子项目中,不同子项目互相干扰,冲突的解决办法

  1. 代码规范统一:制定统一的规范(接口规范,UI规范,commit 规范等)
  2. UI 的统一:不同的子项目使用不同的前缀(CSS,公共组件)
  3. 编程能力统一:不同的同事水平不一样,那么按照中等的水平作为整体的标准(react hook typescript 等技术,根据团队技术水平决定)项目设置成不同的模块,不同人完成不同的模块,只要求接口统一
  4. 增加自动监测模块(单元测试,集成测试)整体项目的水平的保证

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,可以直接访问这些外部的图片。

undefined

这里设置的意思是:只能加载下面的图片

  • 与当前页面相同来源('self')。

  • 数据 URL(data:)。

  • 域名 mt0.google.commaps.googleapis.commaps.gstatic.com(可能是谷歌地图相关功能)

实际场景中遇到一次这个问题

0399 webpack-bundle-analyzer

统计第三方依赖占用的存储大小

https://github.com/webpack-contrib/webpack-bundle-analyzer

This module will help you:

  1. Realize what's really inside your bundle

  2. Find out what modules make up the most of its size

  3. Find modules that got there by mistake

  4. 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 本地编辑器,使用如下

https://cloud.seafile.com/library/c57d6533-edaa-41ba-9b2a-f8bbb1c3aab9/new%20app/typora%20%E6%97%A9%E6%9C%9F%E7%89%88%E6%9C%AC%E6%97%A0%E9%9C%80%E8%B4%AD%E4%B9%B0


Last update: November 9, 2024