阅读 263

打造自己的前端脚手架

本文主要介绍一下个人的一个脚手架项目 useful-cli 搭建过程,功能十分简单,通过useful-cli create命令可以拉取项目中的模板文件到本地,实现快速的启动一个项目,目前支持微信小程序,之后还会补充react、vue等模板。微信小程序使用的是原生开发,模板添加了许多工程化配置,感兴趣的朋友可以看下一篇文章分享:微信小程序原生开发工程化解决方案

useful-cli 项目地址:github.com/yucheng1207…

项目代码分析

项目依赖

首先我们来介绍下useful-cli中用到的一些依赖,这些依赖帮助我们正确的解析命令行数据,拉取到正确的模板代码。

chalk

用于设置终端字符串样式,比如需要输出一段红色字符串。

console.log(chalk.red(`This is a string of red strings`));
复制代码

fs-extra

fs-extra 是 fs 的一个扩展,提供了非常多的便利 API,并且继承了 fs 所有方法和为 fs 方法添加了 promise 的支持。

const fs = require('fs-extra')
// 同步写法
try {
  fs.copySync('/tmp/myfile', '/tmp/mynewfile')
  console.log('success!')
} catch (err) {
  console.error(err)
}
// 异步写法
async function copyFiles () {
  try {
    await fs.copy('/tmp/myfile', '/tmp/mynewfile')
    console.log('success!')
  } catch (err) {
    console.error(err)
  }
}
复制代码

path

path 模块用于处理文件或目录路径。

path.resolve([...paths]):方法将路径或路径片段的序列解析为绝对路径。
path.join([...paths]):方法使用特定于平台的分隔符作为定界符将所有给定的 path 片段连接在一起,然后规范化生成的路径。
path.resolve(__dirname):返回被执行 js 文件的绝对路径
path.resolve(
    path.join(__dirname, 'template-typescript', 'wechatMiniprogram')
) // 返回被执行路径下的template-typescript/wechatMiniprogram的绝对路径
复制代码

inquirer

一组通用的交互式命令行用户界面。如下代码可在命令行中进行选择操作:

const { appType } = await inquirer.prompt([
      {
          name: 'appType',
          type: 'list',
          message: `Please select the type of project you want to create:`,
          choices: [{ name: '微信小程序', value: 'wechat-miniprogram' }],
      },
  ]);
  switch (appType) {
      case 'wechat-miniprogram':
          createWechatMiniprogram(name, options);
          break;
      default:
          console.log(chalk.red('unknow app type'));
          break;
  }
复制代码

minimist

用于解析命令行参数,如下代码可获取命令行输入的参数:

var argv = require('minimist')(process.argv.slice(2));
console.log(argv);
复制代码

commander

完整的 node.js 命令行解决方案。可用于配置命令具体处理函数。

const { Command } = require('commander');
const program = new Command();
program
    .command('create <app-name>')
    .description(`Use ${chalk.green('useful-cli')} to create a new project`, {
        'app-name': 'project name',
    })
    .action((appName, options) => {
        if (minimist(process.argv.slice(3))._.length > 1) {
            console.log(
                chalk.yellow(
                    "\n Info: You provided more than one argument. The first one will be used as the app's name, the rest are ignored."
                )
            );
        }
        ...
    });
复制代码

主要代码

项目代码十分简单,定义create命令,接受到app-name参数后询问要创建的项目类型,选择完项目类型后在执行路径下创建同名文件夹,并到对应的模板目录下(template-typescript)拉取模板文件。

#!/usr/bin/env node
const chalk = require('chalk');
const inquirer = require('inquirer');
const minimist = require('minimist');
const commander = require('commander');
const packageJson = require('../package.json');
const program = new commander.Command(packageJson.name);
const createWechatMiniprogram = require('./createWechatMiniprogram');

program
    .version(packageJson.version, '-v, --version')
    .usage(`create ${chalk.green('<app-name>')}`);

program
    .command('create <app-name>')
    .description(`Use ${chalk.green('useful-cli')} to create a new project`, {
        'app-name': 'project name',
    })
    .action((appName, options) => {
        if (minimist(process.argv.slice(3))._.length > 1) {
            console.log(
                chalk.yellow(
                    "\n Info: You provided more than one argument. The first one will be used as the app's name, the rest are ignored."
                )
            );
        }
        create(appName, options);
    });

async function create(name, options) {
    console.log('createApp', name, options);
    // 选择appType,目前只有小程序
    const { appType } = await inquirer.prompt([
        {
            name: 'appType',
            type: 'list',
            message: `Please select the type of project you want to create:`,
            choices: [{ name: '微信小程序', value: 'wechat-miniprogram' }],
        },
    ]);
    switch (appType) {
        case 'wechat-miniprogram':
            createWechatMiniprogram(name, options);
            break;
        default:
            console.log(chalk.red('unknow app type'));
            break;
    }
}

program.parse(process.argv);
复制代码
// createWechatMiniprogram.js
const chalk = require('chalk');
const fs = require('fs-extra');
const path = require('path');
const templateRoot = path.resolve(
    path.join(__dirname, 'template-typescript', 'wechatMiniprogram')
); // 获取模板路径

async function create(name) {
    const root = path.resolve(name);
    try {
        // 如果不存在的话创建文件夹
        if (!fs.existsSync(name)) {
            fs.ensureDirSync(name);
            console.log(`Folder ${name} has been created.`);
            console.log(`Copying...`);
            fs.copySync(templateRoot, root);
            console.log(`Done.`);
        } else {
            console.log(chalk.red(`Folder ${name} is exist`));
            process.exit(1);
        }
    } catch (error) {
        console.log(chalk.red(`Create miniprogram failed:`, error));
        process.exit(1);
    }
}

module.exports = (...args) => {
    return create(...args).catch((err) => {
        console.log(chalk.red('create wechat miniprogram failed:', err));
        process.exit(1);
    });
};
复制代码

发布

修改完package.json中的版本号后使用npm publish即可发布到npm上。(需要注意的是如果是初次发布要确保npm上没有与项目同名的npm包),第一次发布的话可以看下这篇文章

npm publish
复制代码

使用

直接使用useful-cli create创建项目并选择需要的模板。

npx useful-cli create my-app
复制代码

image.png

文章分类
前端
文章标签