Github address: github.com/jinxuanzhen… If you think it is useful, please give the project a STAR. Thank you

Follow up with “Developing a small application CLI scaffolding from 0 to 1 (part 1) – Creating page/component templates”

You’ve already learned how to build a CLI scaffold, including the ability to quickly generate a startup template. Essentially, scaffolding can do a lot more than that. This article will implement some new features, such as automatic release experience, version number control, and environment variable control

Pain points

I don’t know if you have the experience of sending multiple versions in a day or sending versions to multiple small programs in a day. According to the normal release process of wechat, you need to:

  1. Example Modify the version number/version description
  2. Modifying the Publishing environment
  3. Click the wechat developer tool to upload the experience version
  4. Submit audit
  5. Confirm the environment/version
  6. Click on the release

All the steps 1 and 2 are to modify the config file manually. The fifth step is to confirm the correctness of the manually modified config file. After all, people always make mistakes

Is there a better way not to repeat the same thing and resign? There is natural, since people are not reliable, then it is possible to streamline it naturally

The preparatory work

  • You’d better read the previous article “Developing a small application CLI Scaffolding from 0 to 1 (part 1) — Creating page/component templates” and build a simple demo

  • To learn about some of the CLI capabilities offered by wechat Applet, click here

Let‘ go

In order to shorten the length, the practical operation codes of many subsequent processes will be described in the form of pseudo code, so it is strongly recommended to read the above. If you need more detailed practical operation codes, please go to github warehouse to check

Actual renderings:

Carding process

  • Identify the command line
  • Ask questions and get the version number and version description
  • Invoke the CLI capability provided by wechat to upload the experience version

Is it very easy to find, and the fact is, the whole function is only 60 lines of code ~

The directory structure

The project structure is divided into entry files and configuration files

- lib
	- publish-weapp.js
- index.js
- config.js
- node_modules
- package.json
Copy the code

Config.js is used to record the configuration of some basic constants and default items, such as project path, execution path, etc

Module.exports = {// root directory root: __dirname, // run dir_root: process.cwd(), // small program project path entry:'/'// Project output folder output:'/',}Copy the code

Identify the command line

Use the third-party library COMMANDER to identify command line parameters in the entry file (index.js) and distribute tasks as routes.

#! /usr/bin/env node

const version                       = require('./package').version;                 / / version number

/* = package import
-------------------------------------------------------------- */

const program                       = require('commander');                         // Command line parsing

/* = task events
-------------------------------------------------------------- */
const publishWeApp                  = require('./lib/publish-weapp');               // Release the demo version

program
    .command('publish')    
    .description('Release wechat mini program experience version')
    .action((cmd, options) = > publishWeApp();

/* = main entrance
-------------------------------------------------------------- */
program.parse(process.argv)
Copy the code

Creating interactive commands

Next comes a QA session where you need to arrange the commands you need according to your actual needs. Recall the problems to be solved:

  • Example Modify the version number/version description
  • Modifying the Publishing environment
  • Automatically upload the experience version according to the CLI

The queue looks something like this:

function getQuestion({version, versionDesc} = {}) {
    return [
        // Determine whether to release the official version
        {
            type: 'confirm'.name: 'isRelease'.message: 'Is this an official release? '.default: true
        },

        // Set the version number
        {
            type: 'list'.name: 'version'.message: 'Set the version number of the upload (current version:${version}) : `.default: 1.choices: getVersionChoices(version),
            filter(opts) {
                if (opts === 'no change') {
                    return version;
                }
                return opts.split(':') [1];
            },
            when(answer) {
                return!!!!! answer.isRelease } },// Set the upload description
        {
            type: 'input'.name: 'versionDesc'.message: Write a brief description of the changes made to this version: '.default: versionDesc
        },
    ]
}
Copy the code

The resulting JSON object looks like this:

{isRelease: true.version: '1.0.1'.versionDesc: 'This is a play version.'}
Copy the code

Determines whether to release the official version

The main reason is that the beta version is not a complete release, and the company needs to release the beta version for internal testing, but only the official version changes the local version file, so this question can only be used as a differentiator

Set the version number or version information

Set the version number and description information on the demo version as shown above. Here is a case that only the first question to select the official release will let you set the version number. The test version will use the default version number 0.0.0, which is also a way to distinguish the demo version

  when(answer) {
    return!!!!! answer.isRelease }Copy the code

There are only three questions set: whether to release, set the version number, set the upload description, and of course you can set the other things you want to do

Upload experience version

Looking through the applet’s documentation, it looks like the following key points:

Finding cli Tools

The cli is not installed globally. You need to index the cli tool path as follows: macOS: < installation path >/Contents/ macOS/CLI Windows: < installation path >/cli.bat

MAC installation path If is the default installation is/Applications/wechatwebdevtools app /, plus the cli location is: /Applications/wechatwebdevtools.app/Contents/Resources/app.nw/bin/cli

Windows, the author says there is no such environment, can only be explored by ourselves

Patch up upload command

The official document gives a very detailed description:

# upload path /Users/username/demo project, specify version 1.0.0, version note is initial releaseCli -u 1.0.0 @ / Users/username/demo - upload - desc'initial release'
# upload your code package size information and deposit/Users/username/info. The jsonCli -u 1.0.0 @ / Users/username/demo - upload - desc'initial release' --upload-info-output /Users/username/info.json
Copy the code

Writing upload logic

Basic process: Obtain cli -> Obtain current version configuration -> Problem queue (obtain upload information) -> Perform upload (CLI command) -> Modify local version file -> Success message

/ /. / lib/publish - weapp. Js file
module.exports = async function(userConf) {
   / / cli path
   const cli = `/Applications/wechatwebdevtools.app/Contents/Resources/app.nw/bin/cli`;

   // Version profile path
   const versionConfPath = Config.dir_root + '/xdk.version.json';
   
   // Get the version configuration
   const versionConf = require(versionConfPath);
   
   Anser case: {isRelease: true, version: '1.0.1', versionDesc: 'This is an experimental version '}
   let answer = await inquirer.prompt(getQuestion(versionConf));
   versionConf.version = answer.version || '0.0.0';
   versionConf.versionDesc = answer.versionDesc;          
       
   // Upload the experience version
   let res = spawn.sync(cli, ['-u'.`${versionConf.version}@${Config.output}`.'--upload-desc', versionConf.versionDesc], { stdio: 'inherit' });
   if(res.status ! = =0) process.exit(1);

   // Modify the local version file (when distribution)!!!!! answer.isRelease &&await rewriteLocalVersionFile(versionConfPath, versionConf);
   
   // success tips
   Log.success('Upload the experience version successfully, log in wechat public platform https://mp.weixin.qq.com to obtain the two-dimensional code of the experience version');
}

// Modify the local version file
function rewriteLocalVersionFile(filepath, versionConf) {
    return new Promise((resolve, reject) = > {
        fs.writeFile(filepath, jsonFormat(versionConf), err => {
            if(err){
                Log.error(err);
                process.exit(1);
            }else{ resolve(); }})})}Copy the code

Note You need to create a xdK.version. json version file in the project root directory. For details, see the repository

It looks something like this:

// xdk.version.json {"version": "0.12.2", "versionDesc": "12.2 "}Copy the code

Xdk-cli publish: xdk-cli publish: xdk-cli publish: xdk-cli publish: xdk-CLI publish

Extension: about the version number increment

You can see that the version number section uses the list type instead of the input type. This is because there is a risk of writing the version number incorrectly.

End result:

Instead of expanding here, search for getVersionChoices: github.com/jinxuanzhen…

Resolve packaging tool issues

Gulp -> XDK -cli publish -> gulp -> XDK -cli publish -> gulp -> XDK -cli publish -> gulp -> XDK -> cli publish

What if I forget one? With the

I don’t know if you are still impressed with the hook of wechat developer tool. What you want to achieve is probably such a thing, a pre-processing hook before uploading

This is also easy to implement. First, open a configurable item to the user’s configuration file (xdk.config.js) :

// xdk.config.js
{
    // Publish the hook
    publishHook: {
        async before(answer) {
	        this.spawnSync('gulp');
            return Promise.resolve();
        },
        async after(answer) {
            this.log('Published hook executes ~');
            return Promise.resolve(); }}}Copy the code

App.js to recognize hooks in publish-app.js:

 // The prefix hook function
await userConf.publishHook.before.call(originPrototype, answer);

// Upload the experience version
let res = spawn.sync(cli, ['-u'.`${versionConf.version}@${Config.output}`.'--upload-desc', versionConf.versionDesc], { stdio: 'inherit' });

// The post-hook function
await userConf.publishHook.after.call(originPrototype, answer);
Copy the code

Of course, you need to check whether the hook exists, determine the type, and return some basic methods and properties to the user configuration, such as: log output, command line execution, etc. In my case, gulp is executed before publsih, then publish, and finally log a line of information

Exactly as expected

Solve the environment variable switching problem

Now that we’ve solved the problem of automatic uploads, we need to solve the problem of environment variable switching. Here we also need to use the hook function we just wrote:

{
    // Publish the hook
    publishHook: {
        async before(answer) {
	       this.spawnSync('gulp'[`--env=${answer.isRelease ? 'online' : 'stage'}`]);
           return Promise.resolve();
        },
        async after(answer) {
            this.log.success('Published hook executes ~');
            return Promise.resolve(); }}}Copy the code

If you do not use a compiler, you can also present a env config file and use the fs module to override the environment variable directly

Here is a list of pseudocodes:

Directory structure -app (small program project) -page - app.json... - env.js - xdk.config.js - xdk.version.js - envConf.js // envConf.js module.exports = { ['online']: { appHost1: 'https://app.xxxxxxxxx.com', appHost2: 'https://app.xxxxxxxxx.com', }, ['stage']: { appHost1: 'https://stage.xxxxxxxxx.com', appHost2: 'https://stage.xxxxxxxxx.com', } }; // xdk.config.js publishHook: { async before(answer) { let config = require('envConf.js')[answer.isRelease ? 'online' : 'stage']; fs.writeFile('./app/env.js', jsonFormat(jsonConf), (err) => {if(err){this.log.error(' write failed ')}else {this.log.success(' write succeeded); }}); return Promise.resolve(); }Copy the code

I did not write the problem of packaging tools and environment variables in THE CLI, because the format of environment variables varies from project to project. How to do this should be left up to the developer, which seems more flexible

The last

In short, the use of scaffolding to solve a series of problems from the release to the online, so that no longer worry about switching environment caused by online bugs, no longer worry about writing the wrong version number, confirm the online environment this environment has become a non-strong requirement

The full implementation process is also complete: xdK-CLI publish- > submit, and the entire code is not complicated. Publish-app.js is only 60 lines of code including comments.

Note: In the next part, we will talk about how to make custom commands to help partners adapt to different projects more freely