After three months, I finally have time to write the second article in the scaffolding series. Working in Beijing is indeed much busier than working in Tianjin, and I have no time to touch fish. If you haven’t seen the first article in this series, which gave you a step-by-step guide on how to build a scaffold, read it first and then read it again.

The mini – making cli project address: https://github.com/woai3c/min…

The V3 version of the code is on the V3 branch, and the V4 version of the code is on the V4 branch.

The third version is V3

The third version adds two main features:

  1. Split the project into monorepo organization.
  2. Add command, can passmvc add xxxCommand way to add plug-ins.

monorepo

Let’s start with a quick look at Monorepo and Multirepo. Both are a means of project management, with multirepo keeping different projects in different Git repositories for maintenance, and monorepo keeping multiple projects in the same Git repository. In the V3 version, I’m going to change the Mini-CLI to Monorepo style, maintaining the different plug-ins as separate projects.

After transforming the project into MonorePO, the directory looks like this:

│ ├─ Bass Exercises - @Mvc │ ├─ Bass Exercises - Bass Exercises - Bass Exercises - @Mvc │ ├─ Bass Exercises - Bass Exercises - Bass Exercises - Bass Exercises - Bass Exercises │ ├─ Bass Exercises - Bass Exercises - Router #, └ ├─ Bass Exercises - Bass Exercises - Router #, └ ├─ Bass Exercises - Bass Exercises - Router #, └ ├─ Bass Exercises - Bass Exercises - Router #, ├─ Bass Exercises - Bass Exercises - Bass Exercises - Router #, ├─ Bass Exercises - Bass Exercises - Router # Webpack plug-in └ ─ scripts # commit message validation script has nothing to do with the project Don't need to focus on │ ─ lerna. Json | ─ package. The json

Monorepo transformation process

Install Lerna globally

npm install -g lerna

Create a project

git init mini-cli

Initialize the

cd mini-cli
lerna init

Create a package

lerna create xxx

Since the CLI is the scaffolding core code, there are other plug-ins that need to be called here because you are adding the other plug-ins to the @MVC/CLI dependency

Lerna add @mvc/cli-plugin-babel --scope=@mvc/cli --scope=@mvc/cli

The scaffolding functionality of monorepo-repo is the same as in version 2, except that the plug-in related code is separated into a separate repo, which can then be published separately to NPM.

Advantages of using Monorepo

  1. If you develop in a multirepo manner, if you need to call other plug-ins during local debugging, you need to execute it firstnpm iInstall before use. With MonorePO, you don’t have this problem. You can call other plugins directly in the Packages directory for easy development and debugging.
  2. If more than one plug-in has been modified, executelerna publishYou can publish your modified plug-ins at the same time, rather than publishing them individually.

The add command

The purpose of transforming the project to monorepo-repo is to make it easier to extend later. For example, if you want to add a router to a generated project that does not already support it, you can execute the command MVC Add Router to add a VUE-Router dependency and the associated template code.

Let’s look at the code for the add command:

const path = require('path') const inquirer = require('inquirer') const Generator = require('./Generator') const clearConsole = require('./utils/clearConsole') const PackageManager = require('./PackageManager') const getPackage = require('./utils/getPackage') const readFiles = require('./utils/readFiles') async function add(name) { const targetDir = process.cwd() const PKG = getPackage(targetDir) // ClearConsole () let Answers = {} try {const pluginTip = require(`@mvc/cli-plugin-${name}/prompts`) answers = await inquirer.prompt(pluginPrompts) } catch (error) { console.log(error) } const generator = new Generator(pkg, targetDir, await readFiles(targetDir)) const pm = new PackageManager(targetDir, answers.packageManager) require(`@mvc/cli-plugin-${name}/generator`)(generator, Answers) await generator. Generate () // Download Depends on await pm.install()} module.exports = add

Because the V3 version was still developed locally, the related plug-ins were not released to NPM because the plug-ins could be referenced directly without performing an NPM I installation. When you run the create command on V2 to create a project, all the interactive prompts are placed under the CLI plug-in, but the add command adds a separate plug-in, so you need to add a Prompt.js file under each plug-in (or not if you don’t need it). Inside are statements that interact with the user. For example, when you add the Router plug-in with the add command, you are asked to select the History mode.

const chalk = require('chalk')

module.exports = [
    {
        name: 'historyMode',
        type: 'confirm',
        message: `Use history mode for router? ${chalk.yellow(`(Requires proper server setup for index fallback in production)`)}`,
        description: `By using the HTML5 History API, the URLs don't need the '#' character anymore.`,
    },
]

As you can see from the code logic of the add command, if a new plug-in has a Prompt.js file, it reads the code to pop up the interaction statement. Otherwise, skip over and download directly.

Version 4 V4

The V4 version has made Webpack’s dev and build functions dynamic. The original scaffold generated projects had a build directory with Webpack configuration code in it. The V4 version of scaffold-generated projects does not have a build directory.

This function is implemented by the new mvc-cli-service plug-in. The generated project will have the following two script commands:

scripts: {
    serve: 'mvc-cli-service serve',
    build: 'mvc-cli-service build',
},

When you run NPM run serve, the command mvc-cli-service serve is executed. The code for this block is as follows:

#! /usr/bin/env node const webpack = require('webpack') const WebpackDevServer = require('webpack-dev-server') const devConfig = require('.. /lib/dev.config') const buildConfig = require('.. /lib/pro.config') const args = process.argv.slice(2) if (args[0] === 'serve') { const compiler = webpack(devConfig) Const server = new WebpackDevServer(compiler) server.listen(8080, '0.0.0.0', err => { console.log(err) }) } else if (args[0] === 'build') { webpack(buildConfig, (err, stats) => { if (err) console.log(err) if (stats.hasErrors()) { console.log(new Error('Build failed with errors.')) } }) } else { console.log('error command') }

Here’s how it works (NPM scripts guide) :

The principle of the NPM script is simple. Each time NPM run is executed, a new Shell is automatically created in which the specified script commands are executed. Therefore, any command that the Shell (usually Bash) can run can be written in an NPM script.

In particular, the Shell created by NPM run adds the current directory’s node_modules/.bin subdirectory to the PATH variable, which is then restored to its original state after execution.

If it is serve, start the development environment with a new WebpackDevServer instance. If it’s a build, package it with Webpack.

VUE – CLI Webpack configuration is dynamic, using ChainWebpack to dynamically add different configurations, my demo is directly written to death, mainly because there is no time, so I did not go into the research.

After publishing to NPM

Download the Mini-CLI Scaffold, but you are only downloading the core plug-in MVC-CLI. If this plug-in needs to reference another plug-in, it needs to be installed first and then invoked. So you need to make some changes to the create add command. Let’s take a look at the changes to the create command:

answers.features.forEach(feature => { if (feature ! == 'service') {pkg.devDependencies[' mvc-cli-plugin-${feature} '] = '~1.0.0'} else { Pkg. devDependencies['mvc-cli-service'] = '~1.0.0'}}) await writeFileTree(targetDir, {'package.json': JSON. Stringify (PKG, null, 2),}) await pm.install() // Loadthe corresponding module according to the option selected by the user, Json and render answers.features.foreach (feature => {if (feature! == 'service') { require(`mvc-cli-plugin-${feature}/generator`)(generator, answers) } else { require(`mvc-cli-service/generator`)(generator, Answers)}}) await generator. Generate () // Download dependent await PM. Install ()

The above code is the added logic. After the user selects the required plug-ins, write them to the PKG object, generate package.json file, and then perform NPM install to install the dependencies. Once the plug-ins are installed, read the generator directory/file code for each plug-in to generate templates or add different dependencies again. Then perform the installation again.

Publish the pit encountered

The V3 version of the plug-in has a prefix @mvc, and since NPM packages with the @ prefix are treated as private packages by default, they have encountered some pits. It took quite a while, but then I got tired of it and changed the prefix names of all the plugins to MVC prefix names.

The resources

  • Lerna multi-package management practice
  • vue-cli
  • NPM scripts usage guide