前段脚手架搭建

kingcwt2022-08-28前端脚手架

快速🔜

  • 1 查看当前环境下是否已经安装成功脚手架

执行start命令 如果成功会有提示 否则找不到


正文

从零搭建属于自己的脚手架到发布

初始化项目

  • 1 创建一个文件夹 然后npm init -y 初始化

  • 2 创建一个index.js文件,然后修改package.json文件

  • index.js

// 告诉npm 如何执行下面的脚本命令 简单理解为node执行脚本  
#!/usr/bin/env node  
  • package.json
// bin 项用来指定各个内部命令对应的可执行文件的位置。  
"bin":{
  "start":"./index.js"
}

安装上面需要的依赖插件 [具体使用 点击上面的链接自行查看]

  • commander

编写代码来描述你的命令行界面

  • glob

用来匹配文件,可以查看当前目录下的文件

  • download-git-repo

主要是为了下载你所需要的git项目

  • chalk@4.0.0 [这个版本,主要是为了支持require引入,而不是使用es6]

可以修改文字颜色

  • metalsmith

可以读取和写入文件

  • handlebars

可以构建模版

  • lodash

快速的对js进行一些处理的工具库

  • cross-spawn

主要是对跨平台命令的处理

  • ora@5.0.0[这个版本,主要是为了支持require引入,而不是使用es6]

一个loading库

  • inquirer@6.0.0[这个版本,主要是为了支持require引入,而不是使用es6]

可以提供命令行查询对命令操作进行选择性的交互处理

源码package.json

{
  "name": "template-cli",
  "version": "1.0.6",
  "description": "",
  "main": "index.js",
  "bin": {
    "start": "./index.js"
  },
  "directories": {
    "lib": "lib"
  },
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": ["template","react","antd"],
  "author": "kingcwt",
  "license": "ISC",
  "dependencies": {
    "chalk": "4.0.0",
    "commander": "^9.4.0",
    "cross-spawn": "^7.0.3",
    "download-git-repo": "^3.0.2",
    "glob": "^8.0.3",
    "handlebars": "^4.7.7",
    "inquirer": "6.0.0",
    "lodash": "^4.17.21",
    "metalsmith": "^2.5.0",
    "ora": "^5.0.0"
  }
}

源码index.js

#!/usr/bin/env node

const { Command } = require('commander');
const { promisify } = require('util')
const program = new Command();
const path = require('path');
const glob = require('glob'); // npm i glob -D
const download = promisify(require('download-git-repo'))
const chalk = require("chalk");
const generator = require('./lib/generator');
const inquirer = require('inquirer');
const ora = require('ora');
const install  = require('./lib/install.js');


program
  .name('Project template')
  .description('项目模版')
  .version('0.0.1');

program
.command('create')  // 输入create 命令【必填】
.argument('<project-name>') //  随意输入的参数 这里指输入的项目名称   
.description('创建模版名称')
.action( async (projectName)=>{
  if (!projectName)  program.help();
  const list = glob.sync('*');
  let isExist = list.includes(projectName);
  if(isExist){
    const name = chalk.hex('afcb92').bold(projectName)
    return console.log(`🍠 ${name} folder already exists.`)
  }

  // 选择安装方式  
  inquirer.prompt([
    {
      name:"package",
      type: 'list',
      choices:['yarn','tyarn','cnpm','npm','npx'],
      message:'select the package management'
    }
  ]).then(async(answer)=>{

  // 1. 下载模版
  const colorProjectName = chalk.hex('afcb92').bold(`~/${projectName}`);
  console.log(`Createing a new react app in ${colorProjectName}`)

  let loading = ora('🚗 开始下载模版...').start()
   // 远程模版地址,默认master分支,这里下载的是main分支
   const repoUrl = 'direct:https://github.com/[你的github用户名称]/[仓库名称].git#[分支]'
   await download(repoUrl, projectName, { clone: true });
   const preConsole = chalk.cyan('cd ')+projectName;
   const nextConsole = chalk.cyan(`yarn dev`);
   const currentProjectName = chalk.hex('afcb92').bold(projectName);
  loading.stop();
  loading.succeed('下载模版成功')

  // 渲染模版
  generator({projectName},path.resolve(__dirname,'./template'),`./${projectName}`)

  console.log(chalk.green('Project initialization finished!'))
  console.log(chalk.yellowBright('start install dependencies...'))
  
  // 安装依赖   
  await install({
    cwd: path.join(process.cwd(), projectName),
    package: answer.package,
  }).then(() => {
    console.log(`${preConsole}\r\n${nextConsole}`)
  })
  .catch((error)=>{
    loading.fail(error);
  })
  })

  return;
})


program.parse();

源码lib/generator.js

// 对模板处理  
const Metalsmith = require('metalsmith')
const Handlebars = require('handlebars')
const rm = require('rimraf').sync
const chalk = require('chalk')
const _ = require('lodash')

module.exports = function(metadata = {}, source, destination = '.') {
 if (!source) {
  return Promise.reject(new Error(`无效的source:${source}`))
 }
 
 return new Promise((resolve, reject) => {
  Metalsmith(process.cwd())
   .metadata(metadata) //metadata 为用户输入的内容
   .clean(false)
   .source(source) //模板文件 path
   .destination(destination) //最终编译好的文件存放位置
   .use((files, metalsmith, done) => {
    Object.keys(files).forEach(fileName => { //遍历替换模板
     if (!_.startsWith(fileName, 'src/font')) { //判断是否为字体文件,字体文件不用替换
      const fileContentsString = files[fileName].contents.toString() //Handlebar compile 前需要转换为字符创
      files[fileName].contents = Buffer.from(Handlebars.compile(fileContentsString)(metalsmith.metadata()))
     }
    })
    done()
   }).build(err => { // build
    rm('source')  //删除下载下来的模板文件,‘source’是路径
    if (err) {
     console.log(chalk.red(`Metalsmith build error: ${err}`))
     return reject(err)
    } else {
     return resolve()
    }
   })
 })
}

源码lib/install.js

// 下载封装  
const spawn = require('cross-spawn');
module.exports = function(options){
  const cwd = options.cwd;
  return new Promise((resolve,reject)=>{
    const command = options.package;
    const args = ['install','--save','--save-exact', '--loglevel', 'error'];
    const child = spawn(command, args, {
      cwd,
      stdio: ['pipe', process.stdout, process.stderr],
    })
    child.once('close', (code) => {
      if (code !== 0) {
        reject({
          command: `${command} ${args.join(' ')}`,
        })
        return
      }
      resolve()
    })
    child.once('error', reject)
  })
}

源码template/package.json

// 从github下来的模版项目对应的package.json的替换 这里只处理了一下名称 其他的可以自行处理  
{
  "name": "{{projectName}}",
  "private": true,
  "version": "0.0.0",
  "scripts": {
    "dev": "npm run build:less && vite --host",
    "xxx":...
  },
  "lint-staged": {
    "**/*.ts?(x)": [
      "prettier --write ./src",
      "eslint ./src"
    ]
  },
  "dependencies": {
    "xlsx": "^0.18.5"
    "xxx":...
  },
  "devDependencies": {
    "vitest": "^0.9.3"
    "xxx":...
  }
}

本地运行测试

上面文件内容库等都弄好以后 接下来就是运行测试

1 在当前项目下执行 npm link 建立软链接

2 这个时候就可以执行package.json下的bin字段下你自己输入的命令,我这里是start,所以执行 start create [输入的项目名称]

3 如果你发布以后 需要测试在本地是不是能用 这个时候需要解除软链接 执行npm uninstall -g [当前的项目名称],我这里执行npm uninstall -g template-cli,执行完以后发现start命令找不到就是ok啦

发布

这里简单介绍一下

1 你要发布到npm源 你需要先切换成npm的源 执行npm get registry查看当前链接的源是哪个

2 设置成npm源 npm set registry [对应源的链接],可以安装一个nrm 然后执行nrm ls可以查看你当前环境的所有源 然后设置一下就行

3 在当前项目下执行npm publish发布 然后就可以在npm上看到你的包了 这里你要提交注册一个npm账户哦 具体如何注册就不说了

4 执行npm unpublish [包名] --force 可以删除对应源上面的包 --force 是强制的意思 发布的命令如果失败 也可以加上 --force哦

到这里就结束了 ~ 🚗

会用到的命令

  • 查看全局npm配置命令

npm ls --global --depth 0

  • 解除软连接

npm unlink

  • 强制建立软连接

npm link --force

  • 查看npm源

npm config get registry

  • 设置npm源

npm config set registry [链接]

  • 发布到npm

npm publish

  • 删除npm上的包

npm unpublish [包名] --force

  • npm查看全局的包

npm list -g

  • 删除全局下的某个npm包

npm uninstall -g [包名]

  • nrm ls

查看当前环境下可用的源

使用的库

  • commander

https://github.com/tj/commander.js/blob/HEAD/Readme_zh-CN.md

  • glob

https://github.com/isaacs/node-glob

  • cfonts

https://github.com/dominikwilkowski/cfonts

  • download-git-repo

https://gitlab.com/flippidippi/download-git-repo

  • chalk@4.0.0

https://github.com/chalk/chalk

  • metalsmith

https://github.com/metalsmith/metalsmith

  • handlebars

https://github.com/handlebars-lang/handlebars.js

  • lodash

https://github.com/lodash/lodash

  • cross-spawn

https://github.com/moxystudio/node-cross-spawn

  • ora@5.0.0

https://github.com/sindresorhus/ora

  • inquirer@6.0.0

https://github.com/SBoudrias/Inquirer.js

Last Updated 10/16/2023, 7:06:22 AM
What do you think?
  • 0
  • 0
  • 0
  • 0
  • 0
  • 0
Comments
  • Latest
  • Oldest
  • Hottest
Powered by Waline v2.15.8