cnpm安装webpack_快速打造最强 Webpack 前端工具链

375f94bdacc341de4221605639a37cac.png

当前,前端技术日新月异,公司的团队技术栈和业务场景不同,都会建立自己的前端工程体系。一个好的工程体系能够保证团队的研发流程规范,提高团队的研发效率,能够减少人员流动带来的项目交接和维护成本。2-3个项目还可维护,那20-30个项目?
在 easywebpack 工程体系的最初设计中,考虑前端工程的复杂性和扩展性问题,各种插件都是可插拔设计,可以灵活组装使用,也可以脱离 easywebpack 体系单独使用,从而保证能够基于 easywebpack 体系定制出符合自己的团队的工程体系方案。

8dd9b84af4cee77be6d9e39ff307cf9a.png

easywebpack-cli

easywebpack-cli 主要包括 Command, Action, Config, Ask 四部分,默认集成了常用的功能服务,你可以很方便的集成已有功能和服务,同时通过覆写基类方法自定义实现相关功能。easywebpack-cli 命令注册是通过 commander 插件实现的,默认支持的命令有如下命令。

4051c13ab06eb0824b999c1849aaf88a.png


下面以实现 Egg + React 集成 CLI 为例,具备 easywebpack-cli 所有能力之外,同时根据 Egg + React 的框架形态进行定制,最终实现 res-cli 自定义 CLI 命令行工具。

Initialize

首先初始化一个 npm 代码库,可以通过 easy init 初始化一个简单的 npm package 代码仓库 res-cli, 然后添加 bin/cli.js , lib/command.js , lib/action.js , lib/config.js , lib/ask.js 等文件。同时在 package.json 中配置添加 bin 命令行入口配置接口初始化一个非常的简单的 res 命令行。

// ${root}/package.json
{
  "bin": {
    "res": "bin/cli.js"
  }
}
// ${root}/bin/cli.js

#!/usr/bin/env node

const Command = require('../lib/command');
new Command().run();

接下来就是根据 easywebpack-cli 提供的 Command, Action, Config, Ask 实现自己的 CLI 定制部分。

Command

// ${root}/lib/command.js
'use strict';
const path = require('path');
const EasyCLI = require('@easy-team/easywebpack-cli');
// 自定义 Action, 见下面 Action 实现
const Action = require('./action'); 

module.exports = class ResCommand extends EasyCLI.Command {

  constructor() {
    super();
    // 命令行库名称,日志输出显示
    this.cli.name = 'res-cli'; 
    // 命令行命令
    this.cli.cmd = 'res';
    // 当前 cli 库的根目录
    this.context = path.resolve(__dirname, '..');
    // 需要合并的 webpack.config.js 配置文件路径
    this.program.filename = path.resolve(this.baseDir, 'config/res.config.js');
    // 命令具体逻辑实现
    this.action = new Action(this);
    // 提供给 res init 骨架初始化的配置
    this.boilerplate = require('./ask');
  } 

  // 定义 res tsc 实现方法即可
  tsc() { 
    this.program
      .command('tsc')
      .option('-p, --project [filename]', 'tsconfig.json file path', this.baseDir)
      .description('typescript compile')
      .action(options => {
        this.action.tsc(options);
      });
  }

  command() {
    // 注册自定义命令 res tsc
    this.register('tsc');
    super.command();
  }
};

Action

命令行命令逻辑自定义实现
// ${root}/lib/action.js

'use strict';
const EasyCLI = require('@easy-team/easywebpack-cli');
const Command = require('egg-bin');
const ScriptCommand = require('egg-scripts');
// 自定义 Config 实现,见下发 Config 实现
const Config = require('./config');
module.exports = class ResAction extends EasyCLI.Action {

  // 提供 Cli 内置 Webpack 配置合并钩子, 需要集成到 cli 内部的 webpack 配置,通过复写该方法实现。
  initCustomizeConfig(options) {
    return Config.getResConfig(options);
  }

  // 覆写 dev 命令
  dev() {
    const cmd = ['dev', '--framework', '@easy-team/res'];
    if (EasyCLI.utils.isEggTypeScriptProject(this.baseDir)) {
      cmd.push('-r');
      cmd.push('egg-ts-helper/register');
    }
    new Command(cmd).start();
  }

  // 覆写 debug 命令
  debug() {
    const cmd = ['debug', '--framework', '@easy-team/res'];
    if (EasyCLI.utils.isEggTypeScriptProject(this.baseDir)) {
      cmd.push('-r');
      cmd.push('egg-ts-helper/register');
    }
    new Command(cmd).start();
  }

  // 覆写 start 命令
  start() {
    new ScriptCommand(['start', '--framework', '@easy-team/res']).start();
  }
}

Config

res-cli 内置 Webpack 配置和合并项目自定义 Wepback 处理
// ${root}/lib/config.js

'use strict';
const path = require('path');
const fs = require('fs');
const merge = require('webpack-merge');
const easywebpack = require('@easy-team/easywebpack-react');

// 获取项目自定义 webpack 配置
exports.getResWebpackFileConfig = baseDir => {
  const filepath = path.resolve(baseDir, 'config/res.config.js');
  if (fs.existsSync(filepath)) {
    return require(filepath);
  }
  return {};
};

// 获取 cli 内部默认集成的 webpack 配置
exports.getResConfig = (options = {}) => {
  const { baseDir = process.cwd(), env } = options;
  const baseConfig = {
    baseDir,
    framework: 'react', // 基于 easywebpack-react 扩展 webpack + react 配置方法
    configured: true,   // 表示项目自定义 webpack 配置在这里已经进行 merge 合并了,无需再次合并
    output: {
      path: path.join(baseDir, 'app/public')
    },
    module: {
      rules: [
        {
          ts: true  // res 默认开启 easywebpack 的 typescript 支持
        }, 
        {
          scss: true  //  res 默认开启 easywebpack 的 sass 支持
        },
        {
          stylus: true // res 默认开启 easywebpack 的 stylus 支持
        },
        {
          less: true //  res 默认开启 easywebpack 的 less 支持
        }
      ]
    }
  };
  const resConfig = exports.getResWebpackFileConfig(baseDir);
  return merge(baseConfig, resConfig, options);
};

// 提供 webpack 最终配置的钩子方法,主要提供给项目自定义需要。
exports.getWebpackConfig = (options = {}) => {
  const config = exports.getResConfig(options);
  return easywebpack.getWebpackConfig(config);
};

Ask

easy init 骨架初始化交互式配置实现
  • name:命令行显示文本说明
  • value:唯一的标识
  • pkgName: 下载代码模板的 npm 模块名称
  • choices: 自定义选择,目前支持 name,description,npm(yarn/npm/cnpm安装模式), style (scss/sass/less/stylus样式)自定义配置。
// ${root}/ask.js

'use strict';
const chalk = require('chalk');
exports.boilerplateChoice = [
  {
    name: `Create ${chalk.green('React')} ${chalk.yellow('Server Side Render')} Web Application for Res`,
    value: 'res-react-asset-boilerplate',
    pkgName: 'res-react-asset-boilerplate',
    choices: ['name', 'description', 'npm']
  },
  {
    name: `Create ${chalk.green('React')} ${chalk.yellow('Client Side Render')} Web Application for Res`,
    value: 'res-react-spa-boilerplate',
    pkgName: 'res-react-spa-boilerplate',
    choices: ['name', 'description', 'npm']
  },
  {
    name: `Create ${chalk.green('React')} ${chalk.yellow('Nunjucks HTML Render')} Web Application for Res`,
    value: 'res-react-html-boilerplate',
    pkgName: 'res-react-html-boilerplate',
    choices: ['name', 'description', 'npm']
  },
  {
    name: `Create ${chalk.green('React')} ${chalk.yellow('Nunjucks Asset Render')} Web Application for Res`,
    value: 'res-react-asset-boilerplate',
    pkgName: 'res-react-asset-boilerplate',
    choices: ['name', 'description', 'npm']
  },
  {
    name: `Create ${chalk.green('React')} ${chalk.yellow('TypeScript')} Awesome Web Application for Res`,
    value: 'res-awesome',
    pkgName: 'res-awesome',
    choices: ['name', 'description', 'npm']
  },
];

项目结构

bc9fe9d4b83fd39b21dd9a601b028c06.png

运行效果

验证 cli 可以通过 npm link 或者 npm publish 安装的方式验证 res 命令

  • res --help

1e60a2b08356f03b35ea30a7ea0c0302.png
  • res init

6d169c2153efaa7a1ea3afb3f5c073a3.png
  • res dev

b0d6c95595e5cade427cb40e6b7cbb1e.png
  • res build --size

60973ba76e2f6037ae0d2863d46065ed.png

实际案例

  • Egg + React Node Framework Command Line Tool https://github.com/easy-team/res-cli
  • Egg + Vue Node Framework Command Line Tool https://github.com/easy-team/ves-cli

相关方案

easywebpack · 语雀​www.yuque.com
830eabbc1fa580b7a232fd97232b457c.png
https://github.com/easy-team​github.com
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值