开发问题记录

内存泄露
window.open 会导致内存泄露, 需要在第三个参数增加noopener
window.open(url, '_blank', 'noopener')
Vscode 配置项
Vscode
中配置fixAll
选项会导致Eslint
每次保存的时候出现卡顿,并提示正在保存 xxx, 正在从 Eslint 获取代码
"editor.codeActionsOnSave": {
"source.fixAll.eslint": false, //此处需要将该值设为false
},
上述问题的根本原因是因为某些扩展程序失去响应, 导致保存的过程中受到影响而出现卡顿
解决办法
在 vscode 中,我尝试禁用之前安装的所有扩展,我一一禁用它们,每次禁用后,我通过更改代码然后保存进行测试,但问题仍然存在,直到所有扩展都关闭。
然后我想起还有一些其他内置扩展。我打开扩展程序,然后按左侧栏右上角的三个点,然后我选择
Show running extensions
,Running extensions
将打开,您会在其中找到一些无响应的扩展程序,并且旁边有一个巨大的数字,比所有其他扩展都要大得多。此时可以选择禁用该扩展, 或者删除该扩展重新安装
本地服务设置 cookie
在本地开发中, 如果需要将服务的Cookie
设置一个默认值, 那么可以采用以下两种方法中的任意一种
module.exports = {
devServer: {
proxy: {
'/api': {
// 第一种方法
onProxyReq(proxyReq) {
proxyReq.setHeader(
'Cookie',
'Authorization=Bearer+gold-scalefb23a7ab783442859a3c8b438e50521b;'
)
},
// 第二种方法
headers: {
Cookie: 'myToken=jx42NAQSFRwXJjyQLoax_sw7h1SdYGXog-gZL9bjFU7'
}
}
}
}
}
SSL 证书问题
当 https 页面提示“您的连接不是私密连接”, 有如下解决方案
方案一 使用彩蛋
在 chrome 该页面上,直接键盘敲入这 12 个字符:`thisisunsafe`
注意:鼠标点击当前页面任意位置,让页面处于最上层即可输入
方案二 修改 hsts 配置
在chrome的地址栏里输入 chrome://net-internals/#hsts,把对应的域名从HSTS中删除,如下图:
方案三 修改无效证书配置
Chrome地址栏输入:chrome://flags/#allow-insecure-localhost
允许无效证书选项:
方案四 修改 Chrome 启动参数
windows 系统
1. 找到你的 Chrome 快捷方式.
2. 右键图标,选择属性
3. 找到”目标”文本框,里面的内容是你的 Chrome 程序路径,类似这样 C:\\Users\\Administrator\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe
4. 在这段文本的后面输入一个空格,然后输入-ignore-certificate-errors
5. 修改后的文本应该类似于这样:C:\\Users\\Administrator\\AppData\\Local\\Google\\Chrome\\Application\\chrome.exe -ignore-certificate-errors
6. 点击确定
7. 重新打开你的 Chrome 浏览器
mac 系统
# 打开 /etc/chromium.d/default-flags 编辑,添加一行:
# 其中 --ignore-certificate-errors 是重点,跳过不信任 Error。不加 --test-type 打开浏览器会有警告,加上之后就没事儿了。
# Disable HTTPS Error Report
export CHROMIUM_FLAGS="$CHROMIUM_FLAGS --ignore-certificate-errors --test-type"
方案六 命令行启动
该方式适合类 unix 系统
open -n /Applications/Google\ Chrome.app/ --args --ignore-certificate-errors --ignore-urlfetcher-cert-requests --user-data-dir=/Users/lorain/MyChromeDevUserData/
Maas 代码风格检查配置
maas 项目众多, 问题比较类似, 不支持可选链?.
, 也不支持空值合并 ??
, 本章节记录解决过程
安装依赖
- "eslint": "^7.32.0"
- "eslint-plugin-vue": "^8.2.0"
- "@babel/plugin-proposal-nullish-coalescing-operator": "^7.16.0"
- "@babel/plugin-proposal-optional-chaining": "^7.16.0"
修改.eslintrc
修改之前的 eslint 配置, 加入以下内容即可
module.exports = {
env: {
es2020: true
},
parser: 'vue-eslint-parser',
parserOptions: {
ecmaVersion: 12,
parser: 'babel-eslint'
}
}
修改 babel.config.js
在原有的配置上新增下列两行
module.exports = {
plugins: [
'@babel/plugin-proposal-optional-chaining',
'@babel/plugin-proposal-nullish-coalescing-operator'
]
}
扩展 prettier
加入如下依赖:
- "prettier": "^2.2.1"
- "eslint-plugin-prettier": "^3.3.1"
- "@vue/eslint-config-prettier": "^6.0.0"
修改 eslintrc.js
module.exports = {
extends: ['plugin:vue/essential', '@vue/standard', '@vue/prettier']
}
加入 prettier.config.js
module.exports = {
semi: false,
singleQuote: true,
trailingComma: 'none',
printWidth: 120
}
生产开启 vue-devtools
需要先获取 vue 根实例, 然后再设置方法重新开启 chrome devtools
// Vue 实例是挂载在元素的 `__vue__` 属性上的
app = document.querySelector('#app').__vue__
// 获取此实例的构造函数
Vue = app.constructor
// 获取 `Vue` 基类,只有基类上有 `Vue.config` 属性
while (Vue.super) {
Vue = Vue.super
}
// 尝试打印 Vue.config
console.log(Vue.config)
Vue.config.devtools = true
__VUE_DEVTOOLS_GLOBAL_HOOK__.Vue = Vue
Iframe 通信
通过iframe
嵌入其他页面, 如果两个系统跨域, 那么父窗口无法获取到iframe.contentDocument
, 但是contentWindow
都能获取到。
在多级页面嵌套中, 有三个关键变量self
、top
、 parent
, 他们的区别如下:
- self 总是指向当前窗口的 window
- top 总是指向顶层窗口的 window
- parent 如果存在多级前端, 是指当前窗口的父窗口
在预防CSRF
攻击的处理中, 也能通过self === top
来判断是否为顶层窗口
PostMessage
iframe
的通信中, 经常使用到postMessage
, 该 api 的定义为:
otherWindow.postMessage(message, targetOrigin, [transfer])
该处的otherWindow是指收消息方窗口的引用:
<!--a.html-->
<iframe
id="iframe"
src="http://10.242.168.52:8082/code-segment/postMessage/b.html"
style="display:none;"
></iframe>
<script>
const iframe = document.getElementById('iframe')
iframe.onload = function () {
const data = { name: 'aym' }
// 向domain2传送跨域数据
iframe.contentWindow.postMessage(JSON.stringify(data), '*')
}
// 接受domain2返回数据
window.addEventListener(
'message',
(e) => {
console.log('data from b.html ---> ', e.data)
},
false
)
</script>
关于开发提效
在面对需求频繁变动的前端项目时,主要的挑战在于如何保持灵活性,同时确保项目的可维护性、可扩展性和开发效率。以下是一些常见的解决方案和实践步骤,可以帮助团队应对这种不确定性。
1. 模块化和可配置化设计
- 方案概述:采用模块化和可配置化的开发模式,将项目拆分为可独立开发和维护的模块。例如,对于SDK,建议使用插件式架构,允许功能在不同业务需求间自由组合;对于B端系统,可以将各个功能模块拆分为独立的组件,通过配置来动态组合和调整。
- 步骤:
- 拆分模块:将系统分解为多个独立的模块或功能组件,每个模块负责一个特定的业务功能。
- 抽象配置层:将核心逻辑与外部需求解耦,提供灵活的配置接口,供业务方定制。例如,提供配置文件或者UI面板来调节功能。
- 封装和复用:将常用的功能和组件提取为通用库,供不同的项目复用。
- 已有产品实例:
- Ant Design:通过将界面和组件高度模块化,Ant Design 允许用户根据需求灵活选择需要的功能和样式。
- Vue.js + Vuex:通过Vuex的状态管理和Vue组件的拆分,轻松应对业务需求的变化。
2. 敏捷开发与持续集成
- 方案概述:采用敏捷开发流程,每个迭代都聚焦于快速交付并根据反馈调整。通过持续集成(CI)和持续交付(CD)确保快速响应业务需求的变化。
- 步骤:
- 快速迭代:将大项目分解为小的迭代周期,业务需求变化时可以及时调整,避免一次性投入大量资源。
- 自动化测试:确保每个小版本的功能稳定性,避免因需求变更导致的回归问题。
- 持续交付:将项目集成到自动化构建和部署系统中,快速推送新版本,保证能快速交付并获得反馈。
- 已有产品实例:
- GitLab CI/CD:使用GitLab的CI/CD管道自动化构建、测试和部署过程,可以非常迅速地应对需求变动。
- Jenkins:广泛用于自动化构建和部署,确保每次需求变更后,代码能够快速集成并部署。
3. 动态配置和特性开关
- 方案概述:通过配置文件或特性开关(Feature Flags),动态控制项目中的功能开关。这种方法可以使得不同业务方的需求能够通过简单的配置来调整,而不需要重新开发或者频繁修改代码。
- 步骤:
- 实现特性开关:为项目中的每个业务需求点引入特性开关,依据需求在运行时动态启用或禁用特性。
- 分阶段部署:通过A/B测试或灰度发布控制不同业务方看到不同的功能集,以此来满足定向开发的需求。
- 管理配置和开关:通过配置管理平台(例如LaunchDarkly、ConfigCat等)集中管理不同的特性开关和配置项。
- 已有产品实例:
- LaunchDarkly:一个成熟的特性管理平台,可以在项目中随时启用或禁用不同的功能,帮助团队应对业务需求的快速变化。
- ConfigCat:提供简单的特性开关解决方案,支持多种环境和版本的灵活管理。
4. 微前端架构
- 方案概述:将大型前端应用拆解为多个小型的、独立部署的微前端模块,每个模块负责处理特定的业务需求。这样可以在不影响整体系统的情况下快速调整和扩展业务模块。
- 步骤:
- 拆分应用:根据不同的业务需求,将应用拆分为独立的微前端模块,每个模块可以独立开发和部署。
- 集成平台:为微前端模块创建统一的集成平台,支持不同模块的动态加载和替换。
- 技术选型:可以使用框架如Single SPA、qiankun等来管理微前端应用的加载和交互。
- 已有产品实例:
- Zalando:通过微前端架构将不同的业务模块拆分,每个模块独立开发,最后通过一个主应用进行集成。
- Netflix:在前端微服务的实现上,Netflix采用了微前端架构,使得多个团队可以独立开发和部署不同的功能模块。
5. API驱动开发
- 方案概述:将业务逻辑和前端表现解耦,通过API驱动开发实现前端和后端的分离。前端项目通过接口调用后端服务,业务需求变化时,只需要修改API,前端代码则可以保持不变。
- 步骤:
- 定义统一的API接口:为前端和后端之间提供一致的接口规范,并约定好API的版本管理和扩展。
- 接口文档化:使用OpenAPI、Swagger等工具为API生成文档,方便团队和业务方沟通。
- 模拟接口:通过mock服务,在前端开发过程中模拟后端API,减少前后端依赖。
- 已有产品实例:
- Stripe:采用了强大的API驱动架构,前端与后端通过RESTful API进行高度解耦,业务需求变化时只需要修改API即可。
- Spotify:前后端完全分离,前端通过API获取数据,后端则独立提供服务和数据。
结语
市场上已经有多种成熟的解决方案可以帮助团队应对前端项目中需求频繁变化的问题。通过模块化设计、敏捷开发、特性开关、微前端架构和API驱动开发等手段,团队能够提高开发的灵活性和响应速度,确保项目能够随着业务需求的变化持续交付并保持高质量。
你所在的团队可以根据具体的项目需求、团队能力以及技术栈来选择合适的解决方案,甚至可以结合多个方案来构建更加高效的开发流程。