npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

mytool-xjp

v1.1.6

Published

前端脚手架工具

Readme

安装教程

npm install -g alipic-tool

前面的话

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

效果如下: image

因为用了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的源码。