大家好,我是编程小6,很高兴遇见你,有问题可以及时留言哦。
通过阅读本文你了解到这5大痛点如何避免和解决:
在一次JavaScript脚本问题修复中发现原本正常使用的fs.writeFile
函数抛出了类型异常导致数据无法正常输出到文件,在查询API后发现fs.writeFile(file, data[, options], callback)
函数的callback
参数在v7.0.0
中被标记为需要必选,在v10.0.0
中被要求强制必选。导致这次故障的原因就是在升级NodeJs版本的时候没有考虑到对历史项目影响,并在切换NodeJs版本到v10
以下后验证了这一问题。
%ProgramFiles%\nodejs
;%UserProfile%\.npmrc
;%AppData%\npm\etc\npmrc
至%UserProfile%\.npmrc
。nvm version
查看版本验证安装结果;nvm list [available]
;nvm install <version> [arch]
;nvm uninstall <version>
;nvm use [version] [arch]
。 同样是在协作开发中发现的问题,因为使用了不同的包管理器,导致在本地开发环境一切正常的代码推送远程后在服务器构建中却意外的失败了,但在其他同事的电脑中再次尝试本地构建是可以复现问题的,这是为什么呢?我们在最后查看node_module
中的内容时发现,由于使用的不同的包管理器导致文件拉取出现了差别最终导致的这个问题。这里我们通过一份预安装脚本来限制使用相同的包管理。
通过在install正式执行前通过在进程中获取可以区别当前使用的包管理器的特殊标识来决定是允许还是中断执行。
标识获取:
process.env.npm_config_user_agent
输出结果:
npm/6.14.5 node/v14.17.1 win32 x64
yarn/1.22.10 npm/? node/v14.17.1 win32 x64
// UserAgent方案的完整脚本
// 定义统一包管理器
const allowPM = 'yarn'
const userAgent = process.env.npm_config_user_agent || ''
if (userAgent !== '') {
const pmName = userAgent.substring(0, userAgent.indexOf('/'))
if (pmName !== allowPM) {
console.warn(
`\u001b[33m This repository requires using ${allowPM} as the package manager for scripts to work properly.\u001b[39m\n`
)
process.exit(1)
}
}
标识获取:
process.env.npm_execpath
输出结果:
C:\...\nvm\v14.17.1\node_modules\npm\bin\npm-cli.js
C:\...\npm\node_modules\yarn\bin\yarn.js
const allowPM = 'yarn'
const execpath = process.env.npm_execpath || ''
if (!new RegExp(`${allowPM}`).test(execpath)) {
console.warn(
`\u001b[33m This repository requires using ${allowPM} as the package manager for scripts to work properly.\u001b[39m\n`
)
process.exit(1)
}
only-allow为pnpm包管理器组织开源限制方案,only-allow内部使用which-pm-runs来获取当前执行的包管理器后再进行判断拦截,仅需在安装依赖后调整scripts中的内容即可,在vite项目中有使用。
npm set-script preinstall "npx only-allow yarn"
。
install
命令将会被中断。遵守GitCommit的通用规范是每个优秀项目比不可少的环节,不同的项目需求中会衍生更多的依赖项需要配置,这里我们通过介绍husky7、commitizen/cz-cli、commitlint三大套件的基础使用来让你快速上手拦截住不规范的Commit信息。
npm install husky --save-dev
;npm set-script prepare "husky install"
;npm set-script xxx
在npm7+生效。npm run prepare
,生成.husky
默认文件夹。husky add <file> [cmd]
;hello world
文本到output.txt
文件。npx husky add .husky/pre-commit "npm test"
;.\node_modules\.bin\husky
),这个问题已在npm8中得到了修复。git add .husky/pre-commit
;git commit -m "Keep calm and commit"
。npm uninstall husky
;git config --unset core.hooksPath
。// 如需强制执行要增加参数--force
npx commitizen init cz-conventional-changelog --save-dev --save-exact
npm set-script cm "cz"
;npm set-script
执行需要npm7+。npm run cm
后将启动交互来生成提交信息,提交前请将待提交文件添加到暂存区。npx husky set .husky/prepare-commit-msg 'exec < /dev/tty && git cz --hook || true'
。git commit
后将进入交互命令。 当我们习惯使用统一的规范后就会觉得CLI的方式很慢,这时候我们就可以取消到原有的pre-commit
中的拦截,改用只进行校验的方式来避免偶尔出现的不规范情况。
npm install --save-dev @commitlint/config-conventional @commitlint/cli
// 注意:如果文件内容编码非UTF-8请修改,在windows中可使用记事本重新另存为UTF-8格式。
echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit $1'
验证HEAD~1到HEAD提交是否规范(源文档命令执行会发生错误):
npx commitlint -- --from HEAD~1 --to HEAD --verbose
正确示范: 错误示范:
一些开源项目为了在被使用时可以轻松的上手或减少重复配置都会提供一份最基础的项目模板并配置相应的CLI工具进行拉取创建,在实际项目开发中我们也可以用类似的思想来帮助我们快速创建页面,组件,路由,控制器等。
npm i plop --save-dev
;npm set-script new "plop"
;|-- project name
|-- plopfile.js
|-- plop-templates
| |-- sfc3
| |-- index.hbs
| |-- prompt.js
说明:我们在plop-templates定义的各个模板在导出后均要在plopfile.js集中注册生效。
Vue的单文件组件将代码分割成template、script、style三块,其中template、style的编写风格相差不大。但是在script部分的编写Vue3就会有一些区别:
const actions = {
// 本次需要增加一个模板
type: "add",
// 输出组件的目录
path: `src/components/${name}/index.vue`,
// 生成组件的模板定义
templateFile: "plop-templates/sfc3/index.hbs",
// 收集到得数据
data: {
name,
// 是否包含template
template: blocks.includes("template"),
// 是否包含style
style: blocks.includes("template"),
// 是否包含script
script: blocks.includes("script"),
default: type === "default",
setup: type === "setup",
reactive: type === "reactive",
scoped: scoped,
},
}
Handlebars是一个轻量的语义化模板,我们通过掌握一些简单的模板语法就可以正常使用,除非你要构建更加复杂的组件模板,那么你可以深入学习一下。
使用{{ xxx }}
的形式直接渲染。
条件判断助手代码块开始为{{#if xxx}}
,结束为{{/if}}
,当template为true时渲染中间的内容。
{{#if template}}
<template>
<div>
</div>
</template>
{{/if}}
{{#if template}}
<template>
<div>
</div>
</template>
{{/if}}
{{#if script}}
<script>
export default {
setup () {
return {}
}
}
</script>
{{/if}}
{{#if style}}
<style{{#if scoped}} scoped{{/if}}>
</style>
{{/if}}
在大多数时候我们都特别在乎JavaScript代码的规范,安装了各式各样的校验工具,同样在CSS里面也应该有一份类似的规范来对编写做一定的限制,这样可以避免重复定义的样式被覆盖的情况,也体现了在编写样式时的思路,同样也提高的CSS的阅读性和维护性。
CSScomb是一款专注于CSS、Less、SCSS或Sass的编码样式格式化程序。
// .vscode/settings.json
{
"csscomb.formatOnSave": true, // 保存代码时自动格式化
"csscomb.preset": {
"always-semicolon": true, // 分号结尾
"block-indent": "\t", // 换行格式
"color-case": "lower", // 颜色格式
"color-shorthand": true, // 颜色缩写
"element-case": "lower", // 元素格式
// "eof-newline": false, // 结尾空行
"leading-zero": false, // 保留前导零位
// "lines-between-rulesets": 0, // 规则间隔行数
"quotes": "double", // 引号格式
"remove-empty-rulesets": true, // 剔除空规则
"space-between-declarations": "\n", // 属性换行
"space-before-closing-brace": "\n", // 后花括号前插入
"space-after-colon": " ", // 冒号后插入
"space-before-colon": "", // 冒号前插入
"space-after-combinator": " ", // 大于号后插入
"space-before-combinator": " ", // 大于号前插入
"space-after-opening-brace": "\n", // 前花括号后插入
"space-before-opening-brace": " ", // 前花括号前插入
"space-after-selector-delimiter": "\n", // 逗号后插入
"space-before-selector-delimiter": "", // 逗号前插入
"strip-spaces": true, // 剔除空格
"tab-size": true, // 缩进大小
"unitless-zero": true, // 剔除零单位
"vendor-prefix-align": false, // 前缀缩进
"sort-order": [
// 布局属性
"display", "visibility", "overflow", "overflow-x", "overflow-y",
// 布局属性:浮动
"float", "clear",
// 布局属性:定位
"position", "left", "right", "top", "bottom", "z-index",
// 布局属性:列表
"list-style", "list-style-type", "list-style-position", "list-style-image",
// 布局属性:表格
"table-layout", "border-collapse", "border-spacing", "caption-side", "empty-cells",
// 布局属性:弹性
"flex-flow", "flex-direction", "flex-wrap", "justify-content", "align-content", "align-items", "align-self", "flex", "flex-grow", "flex-shrink", "flex-basis", "order",
// 布局属性:多列
"columns", "column-width", "column-count", "column-gap", "column-rule", "column-rule-width", "column-rule-style", "column-rule-color", "column-span", "column-fill", "column-break-before", "column-break-after", "column-break-inside",
// 布局属性:格栅
"grid-columns", "grid-rows",
// 尺寸属性
"box-sizing","margin","margin-left","margin-right","margin-top","margin-bottom","padding","padding-left","padding-right","padding-top","padding-bottom","border","border-width","border-style","border-color","border-colors","border-left","border-left-width","border-left-style","border-left-color","border-left-colors","border-right","border-right-width","border-right-style","border-right-color","border-right-colors","border-top","border-top-width","border-top-style","border-top-color","border-top-colors","border-bottom","border-bottom-width","border-bottom-style","border-bottom-color","border-bottom-colors","border-radius","border-top-left-radius","border-top-right-radius","border-bottom-left-radius","border-bottom-right-radius","border-image","border-image-source","border-image-slice","border-image-width","border-image-outset","border-image-repeat","width","min-width","max-width","height","min-height","max-height",
// 界面属性
"appearance","outline","outline-width","outline-style","outline-color","outline-offset","outline-radius","outline-radius-topleft","outline-radius-topright","outline-radius-bottomleft","outline-radius-bottomright","background","background-color","background-image","background-repeat","background-repeat-x","background-repeat-y","background-position","background-position-x","background-position-y","background-size","background-origin","background-clip","background-attachment","bakground-composite","background-blend-mode","mask","mask-mode","mask-image","mask-repeat","mask-repeat-x","mask-repeat-y","mask-position","mask-position-x","mask-position-y","mask-size","mask-origin","mask-clip","mask-attachment","mask-composite","mask-box-image","mask-box-image-source","mask-box-image-width","mask-box-image-outset","mask-box-image-repeat","mask-box-image-slice","box-shadow","box-reflect","filter","mix-blend-mode","opacity","object-fit","clip","clip-path","resize","zoom","cursor","pointer-events","touch-callout","user-modify","user-focus","user-input","user-select","user-drag",
// 文字属性
"line-height","line-clamp","vertical-align","direction","unicode-bidi","writing-mode","ime-mode","text-overflow","text-decoration","text-decoration-line","text-decoration-style","text-decoration-color","text-decoration-skip","text-underline-position","text-align","text-align-last","text-justify","text-indent","text-stroke","text-stroke-width","text-stroke-color","text-shadow","text-transform","text-size-adjust","src","font","font-family","font-style","font-stretch","font-weight","font-variant", "font-size", "font-size-adjust", "color",
// 内容属性
"overflow-wrap", "word-wrap", "word-break", "word-spacing", "letter-spacing", "white-space", "caret-color", "tab-size", "content", "counter-increment", "counter-reset", "quotes", "page", "page-break-before", "page-break-after", "page-break-inside",
// 交互属性
"will-change", "perspective", "perspective-origin", "backface-visibility", "transform", "transform-origin", "transform-style", "transition", "transition-property", "transition-duration", "transition-timing-function", "transition-delay", "animation", "animation-name", "animation-duration", "animation-timing-function", "animation-delay", "animation-iteration-count", "animation-direction", "animation-play-state", "animation-fill-mode"
] // 属性排序
}
}
// .vscode/keybindings.json
[{
"key": "ctrl+alt+c", // "cmd+alt+c"
"command": "csscomb.execute"
}]
通过这一篇的学习就不要再为环境不能平滑切换而放弃新功能的尝鲜了。统一的包管理器也不会再有参差不齐的问题出现。规范的GitCommit可以为阶段的总结生成日志,平时的查询也会更加方便。组件级别的模板编写可以在长期迭代的项目中节省时间,规范编码。同样也不能忽略CSS也是前端的一部分,良好的结构同样起到了便于阅读和维护的作用。当然在开发过程中还会有一些可能被忽略掉的痛点,下次整理后再发出来,也欢迎在评论区打出你发现的前端开发痛点还有哪些?✔
高灯科技交易合规前端团队(GFE), 隶属于高灯科技(北京)交易合规业务事业线研发部,是一个富有激情、充满创造力、坚持技术驱动全面成长的团队, 团队平均年龄27岁,有在各自领域深耕多年的大牛, 也有刚刚毕业的小牛, 我们在工程化、编码质量、性能监控、微服务、交互体验等方向积极进行探索, 追求技术驱动产品落地的宗旨,打造完善的前端技术体系。
Github:github.com/gfe-team
团队邮箱:gfe@goldentec.com
作者:GFE(高灯科技交易合规前端团队)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。