前端脚手架构建实践

栏目: Node.js · 发布时间: 5年前

内容简介:在前端工程化过程中,为了解决多项目中,相似度高的工作,便诞生许多前端脚手架,这里记录下自己实现一个简易前端脚手架过程的实践。主要是解决多个页面相似内容的复制粘贴问题,功能类似于Webstorm的Live template,或者Vscode的Snippets。注意哦,用户执行

前面的话

在前端工程化过程中,为了解决多项目中,相似度高的工作,便诞生许多前端脚手架,这里记录下自己实现一个简易前端脚手架过程的实践。主要是解决多个页面相似内容的复制粘贴问题,功能类似于Webstorm的Live template,或者Vscode的Snippets。

思路

  • 预先配置页面模板,预留关键字变量
  • 用户填写关键字变量,生成页面模板,输出到制定目录

用到的包

  • fs

    读写文件模块,这里主要用于读入用户配置文件,输出模板到文件

  • commander

    NodeJs命令行工具,提供了用户命令行输入和参数解析,用户解析用户输入

  • inquirer

    NodeJs交互式命令行工具,询问操作者问题,获取用户输入,校验回答的合法性

  • metalsmith

    文件处理,读写操作

  • handlebars

    将模板中的变量替换为用户输入,编译模板,类似框架如:artTemplate,Jade

  • path

    NodeJs的路径操作库,如合并路径

  • chalk

    命令行输出样式美化

具体实现

  1. 首先在一个新的文件夹,如xxx-tools下 npm init 创建一个node项目,因为是要做成一个npm包的脚手架,所以在包的取名上一定要唯一,即 package.jsonname 字段,避免在发包的时候和网上已经存在的npm包重名,报403没有权限的错。
  2. 在xxx-tools文件夹下创建 bin 文件夹,同时在 bin 文件夹下创建脚本 tempTool 文件,内容如下:
#!/usr/bin/env node

console.log('Hello World');

注意哦, #!/usr/bin/env node 这个是 Linux 规范,用来指明了这个执行脚本的解释程序,要是没有这一行,默认用当前 Shell 去解释这个脚本

  1. package.json 中增加 bin 配置:
"bin": {
    "tempTool": "./bin/tempTool"
  },
  1. 到目前为止,一个简单的前端脚手架实现了,在npm官网注册,在项目里执行 npm login 登录,之后 npm publish 如果一切顺利,npm包提交完毕,可以在其它项目中执行 npm i -g xxx-tools ,安装这个包,执行 xxx-tools 命令,输出 Hello World ,脚手架开发过程中,也涉及到在本地调试,可以直执行 node ./bin/xxx-tools
  2. 现在来加入具体的开发流程,用户的输入,输入信息的读取等等, bin 文件修改如下
#!/usr/bin/env node

const program = require('commander');
const chalk = require('chalk');
const { loadTemplate } = require('../src/lib/writeTemp');

const log = data => console.log(chalk.green(data));

log('初始化模板配置');

program
  .command('create')
  .description('create template')
  .option('-d')
  .action(async function () {
    const result = await loadTemplate();
    result ? null : log('配置完毕');
  });

program.parse(process.argv);

用户执行 create 命令,在这里调用了 loadTemplate 函数,看一下这个函数

// 把模板中的变量替换为用户输入的变量,输出模板到制定文件夹
const Metalsmith = require('metalsmith');
const Handlebars = require('handlebars');
const path = require('path');
const fs = require('fs');
const { askQuestion } = require('./askQuestion');

const loadTemplate = async () => {
  // 从toolrc.json文件读取配置
  const dirPath = process.cwd();
  if (!fs.existsSync('toolrc.json')) {
    throw new Error('toolrc.json配置文件不存在');
  }
  const configJson = path.join(dirPath, 'toolrc.json');
  const config = fs.readFileSync(configJson);
  const { source, dist, questionConfig } = JSON.parse(config);
  const answer = await askQuestion(questionConfig);
  const metalsmith = Metalsmith(__dirname);

  metalsmith
    .metadata(answer)
    .source(path.join(dirPath, source))
    .destination(path.join(dirPath, dist))
    .use(function (files, metalsmith, done) {
      //遍历替换模板
      Object.keys(files).forEach(fileName => {
        const fileContentsString = files[fileName].contents.toString();
        //Handlebar compile 前需要转换为字符串
        files[fileName].contents = new Buffer(Handlebars.compile(fileContentsString)(metalsmith.metadata()));
      });
      done();
    }).build(function (err) {
    if (err) throw err;
  });
};

module.exports.loadTemplate = loadTemplate;

为了方便用户配置,需要用户自行配置一个 toolrc.json 文件,指明模板文件的输入输出目录,和需要用到的

询问变量,示例配置如下:

{
  "source": "/src/template",
  "dist": "/build",
  "questionConfig": {
    "name": {
      "type": "string",
      "required": true,
      "label": "Module name"
    },
    "description": {
      "type": "string",
      "required": true,
      "label": "Module description"
    },
    "namespace": {
      "type": "string",
      "required": true,
      "label": "dva model namespace"
    }
  }
}

source 配置了模板文件的位置, dist 为输出文件的位置, questionConfig 为模板中的关键字,需要用户在交互的命令行中输入,下面这段为利用 inquirer 包,实现命令行交互。

// 遍历问题模板,输出提问

const inquirer = require('inquirer');

const askQuestion =  async (prompts)=> {
  let promptsArr = Object.keys(prompts).map(key => ({
    name: key,
    ...prompts[key]
  }));
  return inquirer.prompt(promptsArr);
}

module.exports.askQuestion = askQuestion

效果如下:

前端脚手架构建实践

因为用了 handlebars 包,模板的定义需要符合其规范,模板文件如下:

import React, { Component } from 'react';
import { connect } from 'dva';
import './style.less';

@connect(state => ({ loading: state.loading }))
class {{name}} extends React.Component {
  state = {};

  componentWillReceiveProps = (nextProps) => {

  };

  render() {
    return ();
  }

}

export default {{name}};

最终输出到 dist 目录的文件,会替换其中双括号里的内容

结束的话

这里只是简单的例子,可以沉淀一些业务场景的模板,通过命令行的方式快速的创建,避免复制粘贴,其实本意是学习一下Node的脚手架 工具 的实现,有兴趣的同学可以看看 babel-cli 的源码。


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

刷屏

刷屏

[美] 凯文•阿洛卡 / 侯奕茜、何语涵 / 中信出版社 / 2018-10-1 / 68.00

1. YouTube流行趋势经理,解密如何打造爆款视频 在视频时代,制造互动,才能创造潮流 用户不再是被动的观众,而是主动的传播者 2. 《刷屏》以行内人视角解读: 病毒视频 粉丝经济 网红产业 平台如何为内容创作者赋能 3. 你是否常常被病毒视频刷屏?你是否觉得很多网红火爆到“无法用常理解释”? 视频时代已经到来,我们每天观看网络......一起来看看 《刷屏》 这本书的介绍吧!

UNIX 时间戳转换
UNIX 时间戳转换

UNIX 时间戳转换

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具

RGB CMYK 转换工具
RGB CMYK 转换工具

RGB CMYK 互转工具