[Solution] 5 major pain points in front-end development

Foreword:

By reading this article, you will know how to avoid and solve these 5 major pain points:

  1. How to switch Node versions gracefully and quickly?
  2. How to unify the use of package managers in a project?
  3. How to develop the habit of standard GitCommit writing?
  4. How to quickly develop similar pages/components without copying?
  5. How to write CSS to make colleagues more willing to read?

Node version manager:

Why manage Node versions?

  1. When we develop more projects, you will find that the version of the NodeJs environment that each project depends on will vary greatly, because we will definitely choose the latest version that is more stable when building a new project, so when we need When maintaining historical projects, it is inevitable to switch to the current version of NodeJs.
  2. When we want to try some new features brought by the Bate version of NodeJs, we need a Bate version of the NodeJs environment.

How to implement Node version switching?

  1. Refuse to download and install repeatedly;
  2. Recommended tools: nvm-windows, nvm .

Practical case sharing:

     In a JavaScript script problem repair, it was found that the function that was normally used fs.writeFilethrew a type exception, causing the data to be unable to be output to the file normally. After querying the API, it was found that the parameters of the fs.writeFile(file, data[, options], callback)function were marked as required in , and were required to be mandatory in . . The reason for this failure is that the impact on historical projects was not considered when upgrading the NodeJs version, and the problem was verified after switching the NodeJs version to the following.callbackv7.0.0v10.0.0v10

Installation Notes:

  1. Because most of the team uses the win system, here is the main introduction to the installation of the win environment;
  2. In order to avoid conflicts before installation, please uninstall the installed NodeJs and check the following directories;
    1. Need to clear: %ProgramFiles%\nodejs;
    2. Need to clear: %UserProfile%\.npmrc;
    3. Recommended backup: %AppData%\npm\etc\npmrcto %UserProfile%\.npmrc.
  3. 下载nvm-windows并按默认推荐安装,安装后重启终端通过nvm version查看版本验证安装结果;
  4. 注意需要使用管理员权限打开终端。

常用命令介绍:

  1. 查看已安装的NodeJs:nvm list [available]
  2. 安装指定版本的NodeJs:nvm install <version> [arch]
  3. 卸载已安装的NodeJs:nvm uninstall <version>
  4. 切换NodeJs版本:nvm use [version] [arch]

更多请参考下图:

nvm (1).png

规范包管理器使用:

     同样是在协作开发中发现的问题,因为使用了不同的包管理器,导致在本地开发环境一切正常的代码推送远程后在服务器构建中却意外的失败了,但在其他同事的电脑中再次尝试本地构建是可以复现问题的,这是为什么呢?我们在最后查看node_module中的内容时发现,由于使用的不同的包管理器导致文件拉取出现了差别最终导致的这个问题。这里我们通过一份预安装脚本来限制使用相同的包管理。

预安装脚本工作原理介绍:

     通过在install正式执行前通过在进程中获取可以区别当前使用的包管理器的特殊标识来决定是允许还是中断执行。

image.png

包管理器标识获取:

  1. UserAgent方案,应用案例是which-pm-runs;
标识获取:
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)
  }
}
复制代码
  1. ExecPath方案,应用案例是vue-next;
标识获取:
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:

     only-allow为pnpm包管理器组织开源限制方案,only-allow内部使用which-pm-runs来获取当前执行的包管理器后再进行判断拦截,仅需在安装依赖后调整scripts中的内容即可,在vite项目中有使用。

  1. 添加命令:npm set-script preinstall "npx only-allow yarn"
    1. 命令执行需要npm版本在v7+;
    2. 安装仅此一步。
  2. 当使用了其他的包管理执行install命令将会被中断。

image.png

GitCommit规范:

     遵守GitCommit的通用规范是每个优秀项目比不可少的环节,不同的项目需求中会衍生更多的依赖项需要配置,这里我们通过介绍husky7、commitizen/cz-cli、commitlint三大套件的基础使用来让你快速上手拦截住不规范的Commit信息。

三大件套介绍(husky7+commitizen+commitlint):

  1. husky7:在git执行的生命周期进行hook,替代git自带的hooks;
  2. commitizen/cz-cli:通过交互的方式生成规范的GitCommit信息;
  3. commitlint:检查GitCommit信息是否规范。

image.png

husky7使用指南:

准备工作:

  1. 安装依赖:npm install husky --save-dev
  2. 增加prepare命令:
    1. npm set-script prepare "husky install"
    2. 注意:npm set-script xxx在npm7+生效。
  3. 初始化husky:npm run prepare,生成.husky默认文件夹。

创建Hook:

  1. 创建Hook命令格式:husky add <file> [cmd]
  2. 创建Hook命令,在git commit前执行npm test:
    1. 修改test命令:输出hello world文本到output.txt文件。
    2. npx husky add .husky/pre-commit "npm test"
    3. 注意:如果执行后仅看到的是帮助提示,可以使用已安装到本地的husky来运行(.\node_modules\.bin\husky),这个问题已在npm8中得到了修复。

验证hook:

  1. 添加暂存:git add .husky/pre-commit
  2. 执行提交:git commit -m "Keep calm and commit"

image.png

卸载hook:

  1. 卸载依赖:npm uninstall husky
  2. 解除Git配置:git config --unset core.hooksPath

更多请参考下图:

实用工具大全.png

commitizen/cz-cli使用指南:

  1. 约定提交消息(AngularJS)

image.png

  1. 约定变更日志:conventional-changelog,同时会涉及standard-versionsemantic-release、workflow等,非本次介绍;
  2. 前提约定:确保npm版本在5.2及以上。

初始化并使用生成Commit信息:

  1. 为项目初始化cz-conventional-changelog:
// 如需强制执行要增加参数--force
npx commitizen init cz-conventional-changelog --save-dev --save-exact
复制代码
  1. 添加执行脚本:
    1. npm set-script cm "cz"
    2. 不推荐使用commit做为key,可能存在冲突导致重复执行,详见文档
    3. npm set-script执行需要npm7+。
  2. 执行npm run cm后将启动交互来生成提交信息,提交前请将待提交文件添加到暂存区。

image.png

使用husky7打通git commint和cz-cli :

  1. 创建./husky/prepare-commit-msg :
    1. npx husky set .husky/prepare-commit-msg 'exec < /dev/tty && git cz --hook || true'
  2. 触发git commit后将进入交互命令。

image.png

更多请参考下图:

实用工具大全 (1).png

commitlint使用指南:

     当我们习惯使用统一的规范后就会觉得CLI的方式很慢,这时候我们就可以取消到原有的pre-commit中的拦截,改用只进行校验的方式来避免偶尔出现的不规范情况。

安装步骤:

  1. 安装必要依赖:
npm install --save-dev @commitlint/config-conventional @commitlint/cli
复制代码
  1. 生成配置文件:
// 注意:如果文件内容编码非UTF-8请修改,在windows中可使用记事本重新另存为UTF-8格式。
echo "module.exports = { extends: ['@commitlint/config-conventional'] };" > commitlint.config.js
复制代码
  1. 创建一个提交信息校验的hook:
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit $1'
复制代码

验证是否可以触发:

验证HEAD~1到HEAD提交是否规范(源文档命令执行会发生错误):

npx commitlint -- --from HEAD~1 --to HEAD --verbose
复制代码

image.png

实际操作GitCommit:

正确示范: image.png 错误示范: image.png

组件级模板开发:

     一些开源项目为了在被使用时可以轻松的上手或减少重复配置都会提供一份最基础的项目模板并配置相应的CLI工具进行拉取创建,在实际项目开发中我们也可以用类似的思想来帮助我们快速创建页面,组件,路由,控制器等。

准备环境:

  1. 安装开发依赖:npm i plop --save-dev
  2. 增加Scripts:npm set-script new "plop";
  3. 推荐目录结构:
|-- project name
    |-- plopfile.js
    |-- plop-templates
    |   |-- sfc3
    |       |-- index.hbs
    |       |-- prompt.js
复制代码

说明:我们在plop-templates定义的各个模板在导出后均要在plopfile.js集中注册生效。

第一个组件模板:

     Vue的单文件组件将代码分割成template、script、style三块,其中template、style的编写风格相差不大。但是在script部分的编写Vue3就会有一些区别:

  1. 使用默认导出创建组件;
  2. 使用setup方言创建组件;
  3. 组件编写使用了defineComponent;
  4. 组件编写使用了reactive;
  5. 组件编写使用了Ts;
  6. 。。。

prompt.js脚本,负责收集用户的操作并汇总答案:

待收集的信息:
  1. Please enter a component name:
  2. Please check the required block:
  3. Please select a type:
  4. Set scoped ?
收集后处理:
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,
  },
}
复制代码

index.hbs模板,负责构建组件的每一块:

     Handlebars是一个轻量的语义化模板,我们通过掌握一些简单的模板语法就可以正常使用,除非你要构建更加复杂的组件模板,那么你可以深入学习一下。

文本渲染:

使用{{ xxx }}的形式直接渲染。

条件判断:

条件判断助手代码块开始为{{#if xxx}},结束为{{/if}},当template为true时渲染中间的内容。

{{#if template}}
<template>
  <div>

  </div>
</template>
{{/if}}
复制代码
可以使用Plopjs内置的Case Modifiers,快速转换变量命名风格:
  • camelCase: changeFormatToThis
  • snakeCase: change_format_to_this
  • dashCase/kebabCase: change-format-to-this
  • dotCase: change.format.to.this
  • pathCase: change/format/to/this
  • properCase/pascalCase: ChangeFormatToThis
  • lowerCase: change format to this
  • sentenceCase: Change format to this,
  • constantCase: CHANGE_FORMAT_TO_THIS
  • titleCase: Change Format To This
示例模板:
{{#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}}
复制代码

CSS属性排序:

     在大多数时候我们都特别在乎JavaScript代码的规范,安装了各式各样的校验工具,同样在CSS里面也应该有一份类似的规范来对编写做一定的限制,这样可以避免重复定义的样式被覆盖的情况,也体现了在编写样式时的思路,同样也提高的CSS的阅读性和维护性。

CSScomb for VSCode:

CSScomb是一款专注于CSS、Less、SCSS或Sass的编码样式格式化程序。 image.png

自定义配置:

  1. CSS排序顺序:布局 → 尺寸 → 界面 → 文字 → 交互;
  2. Custom configuration file : VSCode → Settings → Workspace → Open Settings (json) in the upper right corner;

image.png

  1. Complete configuration, recommended for use in the workspace, configuration from JowayYoung :
// .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"
		] // 属性排序
	}
}
复制代码
  1. Add shortcut key optimization:
// .vscode/keybindings.json
[{
	"key": "ctrl+alt+c", // "cmd+alt+c"
	"command": "csscomb.execute"
}]
复制代码

GIF 2022-3-3 11-07-48.gif

  1. For more configuration options, please refer to the documentation: csscomb options .

write at the end

     Through the study of this article, don't give up the early adopters of new functions because the environment cannot be switched smoothly. The unified package manager will no longer have jagged problems. The standard GitCommit can generate logs for the summary of the stage, and the usual query will be more convenient. Component-level template writing can save time and standardize coding in long iterative projects. It cannot be ignored that CSS is also a part of the front end, and a good structure also plays a role in being easy to read and maintain. Of course, there will be some pain points that may be overlooked during the development process. I will post them next time after sorting them out. You are also welcome to type in the comments area what other front-end development pain points you found?

team introduction

     Gao Deng Technology’s Transaction Compliance Front-End Team (GFE), affiliated to the R&D Department of Gao Deng Technology (Beijing) Transaction Compliance Business Line, is a team full of passion, creativity, and adherence to technology-driven all-round growth. The average age of the team is 27 Years old, there are big bulls who have been cultivating in their respective fields for many years, and there are also calves who have just graduated. We are actively exploring in the fields of engineering, coding quality, performance monitoring, micro-services, interactive experience, etc., pursuing the purpose of technology-driven product implementation, creating Perfect front-end technology system.

  • Vision: To be the most trusted and influential front-end team
  • Mission: Adhere to customer experience first, create more possibilities for business
  • Culture: Courage to take on, in-depth business, teamwork, simple and open

Github:github.com/gfe-team

Team Email: [email protected]

Author: GFE (Gao Deng Technology Transaction Compliance Front-end Team)

Copyright belongs to the author. For commercial reprints, please contact the author for authorization, and for non-commercial reprints, please indicate the source.

Guess you like

Origin juejin.im/post/7078106750187995166
Recommended