前端工程化之脚手架创建工具

概述

开发此工具的目的是为了统一公司前端项目脚手架,技术选型,集成CICD方案,集成内部依赖包等。

原理

跟常规的npm包一样,通过在package.json中配置bin(PATH环境变量软链)安装的时候可以在shell终端使用命令来执行我们的nodejs脚本,通过提问式获取最终配置项,来创建项目的脚手架。

程序设计图:

核心设计

提问式模式(Prompt Design)

  • 将脚手架功能细化成程序运行平台、基础框架选型、脚手架能力、CICD集成方案等模块化能力,通过用户选择将其动态组合起来,最终构建出目标工程。具体代码实现:
js 复制代码
const inquirer = require('inquirer')
// 获取提供给用户的选择项
const getPromptModules = () => {
  return ['feature-x', 'feature-xx', 'feature-xxx', 'feature-xxxx'].map(file =>
    require(`../promptModules/${file}`)
  )
}
const promptAPI = new PromptModuleAPI(this)
getPromptModules().forEach(m => m(promptAPI))
// 展示选项在终端中,合并最终选择项目
const resolveFinalPrompts = () => {
    this.injectedPrompts.forEach(prompt => {
      const originalWhen = prompt.when || (() => true)
      prompt.when = answers => {
        return isManualMode(answers) && originalWhen(answers)
      }
    })
    let prompts = ''
    if (this.featurePrompt.choices.length > 0) {
      prompts = [
        this.presetPrompt,
        this.featurePrompt,
        ...this.injectedPrompts,
        ...this.outroPrompts,
      ]
    } else {
      prompts = [this.presetPrompt, ...this.injectedPrompts, ...this.outroPrompts]
    }
    debug('paxc:prompts')(prompts)
    return prompts
}
const answers = await inquirer.prompt(resolveFinalPrompts())

插件机制(Plugin System)

  • 提供给前端用户选择的内容都通过插件式的方式实现,方便第三方继承和扩展该能力,丰富功能。
  • 有利于将核心能力聚合,对外暴露接口,形成高内聚低耦合的设计方式

具体代码:

js 复制代码
// 获取本地插件
async resolvePlugins(rawPlugins, preset) {
    for (const plugin of rawPlugins) {
      let apply = ''
      if (plugin.isCore) {
        apply = require(`./plugins/core/${plugin.id}`).apply
      } else {
        apply = require(`./plugins/${plugin.id}`).apply
      }
      plugin.apply = apply
      if (!plugin.options) {
        plugin.options = preset
      }
    }
}
// 对插件的执行优先级排序,初始化插件,应用插件
_sortPlugins() {
    const plugins = this.plugins
    for (let i = 0; i < plugins.length; i++) {
      const plugin = plugins[i]
      if (plugin.isCore && i === 0) break
      if (plugin.isCore) {
        plugins[i] = plugins[0]
        plugins[0] = plugin
        break
      }
    }
}
async initPlugins() {
    const pluginIds = this.plugins.map(p => p.id)
    // apply generators from plugins
    for (const plugin of this.plugins) {
      const { id, apply, options } = plugin
      if (apply) {
        const api = new GeneratorAPI(id, this, options, this.preset)
        await apply(api, options, this.preset)
        if (apply.hooks) {
          await apply.hooks(api, options, this.preset, pluginIds)
        }
      }
    }
}
// 生成脚手架文件
async generate({ sortPackageJson = true } = {}) {
    // core plugin first
    this._sortPlugins()
    await this.initPlugins()
    const initialFiles = Object.assign({}, this.files)
    // wait for file resolve
    await this.resolveFiles()
    if (this.pkg) {
      // set package.json
      if (sortPackageJson) {
        this.sortPkg()
      }

      this.files['package.json'] = JSON.stringify(this.pkg, null, 2) + '\n'
    }
    // write/update file tree to disk
    await writeFileTree(this.context, this.files, initialFiles)
}
相关推荐
donecoding39 分钟前
一个 sudo 引发的血案:npm 全局包权限错乱彻底修复
前端·node.js·前端工程化
风骏时光牛马43 分钟前
Raku正则匹配与数据批量处理实操案例
前端
nbwenren1 小时前
2026实测:Gemini 3 镜像站视觉能力实践——拍照原型图,一键生成 HTML+CSS 代码
前端·css·html
Lee川1 小时前
Prisma 实战指南:像搭积木一样设计古诗词数据库
前端·数据库·后端
jinanwuhuaguo1 小时前
(第二十九篇)OpenClaw 实时与具身的跃迁——从异步孤岛到数字世界的“原住民”
前端·网络·人工智能·重构·openclaw
广州华水科技1 小时前
深度测评2026年单北斗GNSS位移监测系统推荐,与高口碑变形监测设备一同引领行业新风尚
前端
Alice-YUE2 小时前
【js高频八股】防抖与节流
开发语言·前端·javascript·笔记·学习·ecmascript
是上好佳佳佳呀3 小时前
【前端(十一)】JavaScript 语法基础笔记(多语言对比)
前端·javascript·笔记
CDN3604 小时前
排查实录:网站偶发502/504错误?360CDN回源超时配置与日志分析技巧
前端·数据库