前端工程化基建探索(3)定制脚手架模板——前端新建项目的“反卷利器”

5,030 阅读12分钟

本文为稀土掘金技术社区首发签约文章,14天内禁止转载,14天后未获授权禁止转载,侵权必究!

前言

说到脚手架,Vue/React技术栈的的同学,马上能想到vue-clicreate-react-app,他们能快速帮我们初始化一个前端项目。但是随着业务的叠加,公共的脚手架往往不能满足具体业务团队的实际开发需求。大多数前端团队,在公司业务的开发中,多少会经积累部分前端成熟的资产,例如接口请求的封装、公共组件和函数的封装、换肤方案、国际化方案、打包发布配置等。如果我们自己定制有一个企业级的脚手架,这些东西都可以集成在脚手架上,当公司前端团队新开一个项目的时候,直接就通过脚手架模板,新建一个前端的基础项目,是不是很省时省力。下面我们就一起来探索,如何定制脚手架吧!

本文目录

(一)前端开新项目之痛与脚手架的价值
(二)了解脚手架模板中的技术细节
(三)从0到1创建和发布一个简易脚手架模板
(四)企业级脚手架模板搭建实操

本文是【前端工程化基建探索】的第3篇,上一篇 前端工程化基建探索(2)从内部机制和核心原理了解npm,看它何“咸鱼翻身”

一、脚手架背景与价值

1.1 前端开新项目之痛

让我们一起回顾一下,现代前端工程化从0到1前端开发流程:

  1. 确定项目技术栈,初始化项目

  2. 安装配置项目技术栈全家桶。 Vue/React、TypeScript、CSS 预处理器(SAAS/LASS)、路由、状态管理等等.

  3. 配置项目文件。通过安装与配置各种 Loader 、插件和其他配置项、选择和调试辅助工具(代码检查工具和单元测试工具),来优化生产或开发环境,优化构建流程,针对开发/生产环境进行配置。

  4. 编写业务代码。通用工具方法、通用样式、通用请求库处理HTTP请求、内部组件库、埋点监控...

  5. 发布上线。业务代码编写完成后,还需要对其进行构建打包、上传服务器、域名绑定、区分测试正式环境、支持回滚...等持续集成、持续部署操作。

公司新启一个项目,在较短的时间内搭建出一个完备的前端项目基础环境是比消耗劳动力的,每一项配置都是需要验证,有时候可能一个库版本的问题都能引发一些“血案”。当然正如上文说的,团队有积累公司项目级别的前端资产,但是要搬到新的项目上来,而且有时候复制粘贴(ctrl + c, ctrl + v),引用和资源缺胳膊少腿的,各种报错得处理,这种重复性劳动,想必每个前端人都不愿意多干!

1.2 脚手架意义

通过上面的开新项目流程回顾,在开启一个新项目的时候,前端脚手架的作用就显得意义重大。代码里任何轮子存在的意义都是提升前端研发整个流程的效能,脚手架也一样,我们期待它能:

  • 自动化:避免团队前端资产迁移到新项目的工作;通过命令行操作。
  • 标准化:通过脚手架模板创建项目;自动生成项目需要的目录。

下面我们了解一下脚手架模板中的技术细节。

二、了解脚手架模板中的技术细节

2.1 一代经典 Vue CLI()

image.png

Vue CLI 是一个基于 Vue.js 进行快速开发的完整系统,提供: 通过 @vue/cli 实现的交互式的项目脚手架。 通过 @vue/cli + @vue/cli-service-global 实现的零配置原型开发。

  • 一个运行时依赖 (@vue/cli-service),该依赖:

    • 可升级;
    • 基于 webpack 构建,并带有合理的默认配置;
    • 可以通过项目内的配置文件进行配置;
    • 可以通过插件进行扩展。
  • 一个丰富的官方插件集合,集成了前端生态中最好的工具。

  • 一套完全图形化的创建和管理 Vue.js 项目的用户界面

(1)当我们全局安装npm install -g @vue/cli ,它安装到哪里去了呢?

以win11为例,它是安装在了C:\Users\ {{YourUserName}} \AppData\Roaming\npm\node_modules
ps:{{YourUserName}} 是你的本计算机的用户名称,需要根据自身实际情况修改。当然只要你全局npm安装的都在这个目录下

image.png

(2)我们全局执行的vue命令,到底执行的是哪个文件呢?

继续向前探索它的目录,node_modules/@vue/cli/bin/vue.js打开这个vue.js文件,首先映入眼帘的第一行:

#!/usr/bin/env node

这里#可不是注释咯,而是Shell编程的Sha-Bang(#!) 的规范,作用是告知该脚本使用的哪种命令解释器,这里就相当于执行 node vue.js是一样的。如果你感兴趣,可以继续阅读这里的代码,比如你还可以发现const program = require(``'commander'``); commander.js 是node命令行解决方案。这里的源码,我们会通过下文自己定制一个脚手架的时候来顺带说一下。 image.png

此刻你心里多少有些疑惑:

(3)为什么安装的是@vue/cli,但是注册的命令却是vue呢?

我们来看一下@vue/clipackage.json

{
  "name": "@vue/cli",
  "version": "5.0.4",
  "description": "Command line interface for rapid Vue.js development",
  "bin": {
    "vue": "bin/vue.js"
  },
  ...... }

这里面通过bin指定了可执行文件的命令名以及可执行文件的路径,npm安装一个依赖时,如果该依赖的package.json中指定了bin的信息,那么同时会创建一个全局的软连接指向该命令所对应的可执行文件。有兴趣的可以看看npm的官方文档:package.json中bin的作用

只是可惜 官网显示 ⚠️ Vue CLI 现已处于维护模式!

2.2 create-vue

Vue CLI 承载了一批用Vue技术栈前端人的回忆,现在官方推荐使用 create-vue 来创建基于 Vite 的新项目。

image.png

2.3 create-vue和Vue CLI的不同之处

(1) Vue CLI基于webpack,而create-vue基于Vite。Vite支持Vue CLI项目中大多数已配置约定的开箱即用,并且由于其极快的启动和热模块替换速度,提供了显著更好的开发体验。

(2) create-vue本身只是一个搭建工具:它根据您选择的功能创建一个预先配置的项目,并将其余的任务委托给Vue。以这种方式构建的项目可以直接利用与rollup兼容的Vite插件生态系统。

2.4 脚手架都做了哪些事情

我们拿Vue CLI来分析:

一、对 HTML 和静态资源 的处理

public/index.html 文件是一个会被 html-webpack-plugin 处理的模板,在构建过程中,资源链接会被自动注入。另外,Vue CLI 也会自动注入 resource hint (preload/prefetchmanifest 和图标链接 (当用到 PWA 插件时) 以及构建过程中处理的 JavaScriptCSS 文件的资源链接。也支持多页面应用构建。

二、 CSS 相关

Vue CLI 项目天生支持 PostCSSCSS Modules 和包含 SassLessStylus 在内的预处理器,你可以在创建项目的时候选择预处理器 (Sass/Less/Stylus)

三、webpack 相关

调整 webpack 配置最简单的方式就是在 vue.config.js 中的 configureWebpack 选项提供一个对象:

// vue.config.js
module.exports = {
  configureWebpack: {
    plugins: [
      new MyAwesomeWebpackPlugin()
    ]
  }
}

你可以进行配置或修改已经有的loader,修改插件plugins,还有一些其他的操作

四、模式和环境变量

默认情况下,一个 Vue CLI 项目有三个模式:

  • development 模式用于 vue-cli-service serve
  • test 模式用于 vue-cli-service test:unit
  • production 模式用于 vue-cli-service build 和 vue-cli-service test:e2e

也可以自行修改 --mode 参数定制自己模式

五、构建目标

当你运行 vue-cli-service build 时,你可以通过 --target 选项指定不同的构建目标。它允许你将相同的源代码根据不同的用例生成不同的构建。你也可以通过命令构建一个库。

通过上述Vue CLI 的了解,我们就对这脚手架工具提供的构建集成能力有了一个大概的了解。这有助于我们在使用具体工具时快速定位问题的边界,当我们自己设计脚手架的时候,我们也可以参照和借鉴。下面,我们再来探索定制专属脚手架模板。

三、如何创建一个简易的脚手架

3.1 手动创建一个自己的cli

我们将从头开始介绍如何开始创建一个 caohq-cli 脚手架模板,开始动手:

$ mkdir caohq-cli  && cd caohq-cli 
$ npm init -y // 初始化 package.json

增加一个命令入口,指向可执行文件,比如当我们运行 caohq 命令时,需要对应一个 node 执行文件,我们可以在 package.json 文件中指明 bin 来配置入口:

{ 
"name": "caohq-cli", 
"version": "1.0.0",
"description": "caohq-cli",
"bin": { "caohq": "bin/index.js" },
"main": "index.js", 
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1" 
},
 "keywords": [],
 "author": "",
 "license": "ISC" 
 }

我们先在index.js写一些内容测试一下:

 #!/usr/bin/env node
console.log('hello cao-cli');

然后执行:npm link 将caohq软连接到本机全局命令

image.png

于是我们就可以愉快的玩耍了,在控制台执行 caohq,我们可以看到打印出来了console.log('hello cao-cli') 说明我们的 cli雏形已经完成!
image.png

3.2 发布自己的cli

目前caohq命令只有我们自己本机可以用,要想其他人也能安装使用,需要将它发布到npm,发布流程:

  • 注册npm账户,已有账户的可直接登录
  • 控制台输入npm login登录,需要输入username、password、email
  • 控制台输入 npm publish 发布

image.png
类似这样,就发布成功了,我们可以在npm里看到自己cli。值得一提的发布需要把npm的源应是npm官方源。 image.png 对于组件和插件相关详细介绍,可以参考我早年发布的《从开发到发布一款基于Vue2x的响应式自适应轮播组件插件VueSliderShow》

3.3 为自己Cli 创建命令

从上面我们分析 Vue Cli 可以看到它支持很多命令和参数,用户在命令行中输入后,脚手架会做出对应的操作。看它的源码是通过commander(是 Ruby 命令行执行补全解决方案)来解析这些命令和参数的,我们这里也一样先安装它:npm install commander

3.3.1 帮助(--help) 和查看版本 (-v)

#!/usr/bin/env node
const program = require('commander')
const {name, version} = require('../package.json')

// 查看版本号
program.name(name).version(version).option('-v,--version','查看版本号')
program.parse(process.argv)

我们可以运行一下即可发现commander内部给我们定义了帮助命令--help(简写-h),通过读取package.json的信息,查看版本号,版本号可以自定义'-v'。

image.png

3.3.2 模拟用户选择项配置

vue Cli的时候,我们会有这个自定义选择配置项,它是怎实现的呢?

image.png 我们查看源码 发现它是通过inquirerjs库,来实现命令行中与用户进行交互,感兴趣的同学可以自行实现这个功能,下面我们第四节会接

// 位置在 "C:\Users\{{username}}\AppData\Roaming\npm\node_modules\@vue\cli\lib\create.js"
const fs = require('fs-extra')
const path = require('path')
const inquirer = require('inquirer')
const Creator = require('./Creator')
const { clearConsole } = require('./util/clearConsole')
const { getPromptModules } = require('./util/createTools')
const { chalk, error, stopSpinner, exit } = require('@vue/cli-shared-utils')
const validateProjectName = require('validate-npm-package-name')
...

3.4 其他创建脚手架工具

Yeoman 作为主打自由制作和分享脚手架生成器的开源工具,Yeoman为制作生成器提供了丰富的 API 和 详细的文档。

四、企业级脚手架模板搭建实操

4.1 企业级脚手架搭建的思考和设计

我们通过日常开发进行一个具体的需求图

image.png

-第一步,通过命令行创建项目

  • 第二步,我们要把模板先放到git上(比如github/gitlab,私有库),然后供用户选择
  • 第三步,选择下载,把模板下载到本地
  • 第四步,初始化项目安装依赖

4.2 企业级脚手架模板开发

4.2.0 检查更新版本

第一步,在终端输入命令行 caohq xxx, 我们检查一下cli的版本,是否是最新的,如果不是最新的给出提示更新,用户可以选择是否更新版本

1667368248602.png

这里实现的方式思路是:

  1. 通过axios 获取远程npm 上的版本,和本地做对比
async function getLatestVersion(id, range = "") {
  const registry = "https://registry.npmmirror.com";
  return axios.get(
    `${registry}/${encodeURIComponent(id).replace(/^%40/, "@")}/${range}`
  );
}

备注:这里把npm的源设置为淘宝镜像,会快一些

  1. 如果本地的更旧则自动去执行npm update -g caohq-cli 更新他
async function checkVersion() {
  const { latestVersion, nowVersion } = await getVersions();
  console.log(latestVersion, nowVersion);
  if (semver.lt(nowVersion, latestVersion)) {
    inquirer
      .prompt([
        {
          name: "update",
          type: "confirm",
          message: "检测到caohq-cli有新版本, 是否更新到最新版本?",
        },
      ])
      .then((answers) => {
        if (answers["update"]) {
          updateCli();
        }
      })
      .catch((err) => {
        console.log(chalk.red(err));
      });
  }
}

基础库使用情况:
(1)semver,- npm使用的语义版本解析器。
(2)inquirer,- 通用交互命令行用户界面的集合。
(3)chalk,- 终端字符串样式美化。
(4)child_process,- 创建一个衍生的 shell, 然后可以在衍生的 shell 之中执行命令。
(5)ora,- 终端 Spinner 等待动画美化

备注:
inquirer版本(^9.0.0)和ora(^6.0.0)以上是ESM模块,这意味着不能再使用commonjs语法require(' Inquirer '),因为这里是node启动, 推荐低版本的inquirer版本(^8.0.0)和ora(^5.1.0)。

4.2.2 创建项目

第二步,在终端输入命令行 caohq creat xxx, 创建一个项目,并拉取项目模板 这里实现的方式思路是: (1)把模板项目先上传到代码仓库
(2)用户选择模板项目名,然后通过项目名,拿到远程连接,下载并解压到本地到本地

4.2.3 初始化项目

待更新

最后

定制脚手架模板——新开项目,“偷懒”才是第一生产力,它的核心目的就是提升我们前端人的开发效率,它没有一个固定的形态可言,大家可以根据自己公司团队的实际情况进行设计,当然很重要一个环节是自己对模板项目的封装,模板项目,这里都是自己前端团队的精华,模板项目可以托管到自己的内网也可以发布到github/gitlab。本文demo后续会完整将会发布到caohq-cli

下一篇: 前端工程化基建探索(4)从源码出发探索理解webpack核心特性