寫一個基於webpack的cli

寫一個基於webpack的cli

更好閱讀體驗請訪問:zhangzippo.github.io/posts/2019/…html

前言

咱們常常接觸到各類各樣的前端腳手架和cli工具,像vue-cli就是一款基於webpack的cli工具,咱們有時候也有針對本身個性化項目快速構建的需求,這時候咱們能夠本身寫一個cli工具。前端

準備

這裏咱們介紹基於webpack去寫一個cli工具,從前日後講,咱們寫一個cli,首先要先定義命令,經過命令觸發webpack的構建流程。那麼咱們基本上須要如下幾個工具包:vue

commander:命令行接口的完整解決方案,能夠方便的建立自定義命令行 inquirer:用於建立可交互的命令行 webpack4: 構建的基礎 有了以上幾個核心工具包以後咱們就能夠開始編寫咱們的cli工具了node

開始

先看一下咱們的工做目錄:webpack

├── bin   --定義自定義命令
├── src
│   ├── build   -- 構建流程
│   ├── develop  -- 開發流程
│   ├── produce
│   └── utils
└── webpack  --webpack配置文件
複製代碼

配置命令

打開package.json,建立bin字段,爲咱們的命令起一個名字(例如block),執行文件指向咱們的bin目錄。git

"bin": {
    "block": "./bin/block-cli.js"
  },
複製代碼

這意味着咱們的命令是以block開頭的,例如block build,block init 等等。而後咱們進行block-cli.js的編寫,注意這個文件的開頭必定要有#!/usr/bin/env node,關於這行的做用你們就自行百度吧。這裏咱們須要引入commander這個工具包了。這裏簡單介紹一下commander工具的用法:github

#!/usr/bin/env node
const program = require('commander');
/**
 * project init
 */
program
  .command('init')
  .description('project init')
  .action(() => {
    init();
  });
/**
 * create modules and pages
 */
program
  .command('create <paths...>')
  .description('create module‘s or page’s path')
  .action((paths) => {
    createTemplete(paths);
  });
/**
 * build progress
 */
program
  .command('build')
  .option('-m, --module [module]', 'Specified the build module')
  .option('-p, --page [page]', 'Specified the build page')
  .description('build the project')
  .action((options) => {
    process.env.NODE_ENV = 'production';
    const build = require('../lib/build/build');
    build(options.module, options.page);
  });
program.parse(process.argv);
複製代碼

咱們主要使用到3個方法,option,command,action, 這裏分別介紹一下,option爲咱們建立命令的相關參數,例如commander會爲咱們建立一個默認的選項--help,例如咱們能夠執行block --help,這時控制檯會輸出咱們定義的全部命令以及選項參數的幫助信息,以下:web

$ block --help 
Options:
  -V, --version                  output the version number
  -conf, --config <config-name>  output the info of target config
  -h, --help                     output usage information

Commands:
  init                           project init
  create <paths...>              create module‘s or page’s path

複製代碼

若是咱們想自定義幫助信息的輸出,咱們能夠這樣作(當調用--help時會觸發--help事件執行這個回調):vue-cli

program.on('--help', () => {
  console.log(`\r\nRun ${chalk.greenBright('block <command> --help')} for detailed usage of given command.`);
});
複製代碼

下面來看第一行第一行咱們調用command('init'),咱們就建立了一個init命令(block init).description爲該命令建立一個描述,這樣會在幫助信息裏面顯示出來,action裏是咱們要爲這個命令執行的事情,這裏咱們執行了一個init方法,該方法內容是建立幾個固定的目錄這裏就不展開了。 咱們的第3個命令block build,是命令結合參數的用法,能夠看到咱們調用了.option方法設定了兩個參數,-m和-p全稱module和page,我這裏的邏輯是構建特定的模塊和頁面。這段寫法在執行的時候這樣: block -m a -p b action中的options參數中包含這兩個option的值,program.parse(process.argv)方法放到命令的最後,這個方法會終結命令的執行。json

配置構建流程

這裏咱們能夠把咱們預先定義好的webpack配置文件放到咱們webpack文件中,這裏就不舉例子了,你們使用本身的配置文件便可。

執行構建流程

既然是咱們本身定義的cli工具,在使用的時候咱們就再也不使用webpack的cli調用方式了,好比咱們正常執行構建的時候會使用命令webpack --config,在咱們本身的構建工具中咱們應該更優雅的採用webpack的node-api方式執行構建,例子:

import webpack from 'webpack';
import configuration from '../../webpack/webpack.config';

module.exports = () => {
  webpack(configuration, (err, stats) => {
    if (err) {
      console.error(err.stack || err);
      // if (err.details) {
      //   console.error(err.details);
      // }
      return;
    }
    console.log(stats.toString({
      colors: true,
      env: true,
    }));
    const info = stats.toJson();
    if (stats.hasErrors()) {
      console.error(info.errors);
    }

    if (stats.hasWarnings()) {
      console.warn(info.warnings);
    }
  });
};
複製代碼

這裏的configuration就是咱們預先準備的webpack配置文件,咱們調用webpack()方法將配置傳入,回調裏包含err和stats兩個參數負責輸出錯誤信息和咱們平時看到的構建流程的信息。 咱們有時候也可能會用到webpack-dev-server,它也是提供node-api方式調用的,下面是例子:

import webpack from 'webpack';
import path from 'path';
import webpackDevServer from 'webpack-dev-server';
import merge from 'webpack-merge';
import chalk from 'chalk';
import getCommonConfig from '../utils/getCommonConfig';

module.exports = (modules = '*', pages = '*') => {
  const rootPath = process.cwd();
  const configuration = merge(getCommonConfig('development', modules, pages), {
    mode: 'development',
    devtool: 'source-map',
    plugins: [
      new webpack.NamedModulesPlugin(),
      new webpack.HotModuleReplacementPlugin(),
    ]
  });
  const options = {
    contentBase: path.join(rootPath, 'static'),
    overlay: true,
    open: false,
    hot: true,
    compress: true,
    port: 8081,
    stats: {
      colors: true,
    },
    host: 'localhost',
    publicPath: '/'
  };
  webpackDevServer.addDevServerEntrypoints(configuration, options);
  const compiler = webpack(configuration);
  const server = new webpackDevServer(compiler, options);
  server.listen(8081, 'localhost', () => {
    console.log(chalk.greenBright('block dev-server listening on port 8081'));
  });
};
// module.exports = serverStart;
複製代碼

這邊爲了支持hotreload咱們須要調用 webpackDevServer.addDevServerEntrypoints,另外使用api的時候以往咱們寫在配置文件中的devserve的配置咱們以這個方法的options傳入,不須要再在配置文件中定義了。 咱們把執行的方法導出,在命令行定義處使用,就完成了咱們自定義的cli工具的調用。

最後

以上咱們就完成了一個簡單的cli工具的基本流程,你們能夠根據本身的須要去豐富流程。

相關文章
相關標籤/搜索