A few days ago, I was learning how to get started with Webpack. Later, I tried to build a simple React development environment by myself. Later, I wondered if I could write a simple scaffolding to avoid the need to configure a simple development environment each time. Configuring a bunch of functionality that you probably won’t use is redundant, so write your own super simplified scaffolding that handles only ES6 code, JSX syntax, and CSS modules, so it meets the basic requirements.

The NPM command was called using Node’s child_process.spawn method. The NPM command was called using Node’s child_process.spawn method. Then I happened to see two articles written by @Jsonz: Create-react-app scaffolders for create-react-app scaffolders for create-react-app scaffolders for create-react-app scaffolders Finally, I wrote a simple (CAN) simple (FEI) React scaffolding. Of course, there are many shortcomings, but this learning process is worth recording.

This article records the following knowledge:

  • How to develop a simple scaffold using Node.
  • How to publish your NPM module and customize commands.

React scaffolding development

Create-react-app is a very successful and fully functional scaffolding. It takes many aspects into account, such as using NPM or YARN, such as NPM and Node version, logging and printing, and many other aspects of the development environment. In addition to basic React development, create-App has the following functions: Images, PostCSS, sASS, graphQL, and so on are also considered. Due to its limited capability, the scaffolding developed in this paper only covers the processing of basic modules, excluding pictures, Sass… And so on.

Scaffolding is used to set up a standard directory for React development and configure the Webpack tool so that changes can be made directly in the standard directory during development, and then the local server or package app can be started using the configured command. The scaffold should therefore include a template folder containing all files or directories that should be copied to the user’s project folder. When using scaffolding, copy the contents of the template folder to the user project folder, then modify the package.json configuration file, and finally install all modules. This is the basic work done by the scaffolding I developed.

Scaffold works directory structure is as follows:

ROOT │.gitignore │.nPMignore │ LICENSE │ Package-Lock. json │ package.json │ ├─dist ├─package │ Create-react. js │ ├ ─templates │.babelrc │.gitignore │ readme.md │ webpack.base.conf ├─ trash ├─ SRC │ ├.css │ ├.html │ index.txt │ ├─ ├.txtCopy the code

According to my previous article, the minimum standard directory structure for setting up a React development environment should be as follows:

ROOT │.babelrc │.gitignore │ readme.md │ webpack.dev.conf.js │ Webpack.dev.conf.js │ Webpack.prod.conf.js │ ├─dist └─ SRC │ index.css │ index.html │ index.js │ ├ ─ ├ ─ ├.txtCopy the code

The templates folder in the scaffold root directory should contain the above files, and the contents of the files can be customized.

Also according to the previous article, the main modules to be installed are:

'webpack', 
'webpack-cli', 
'html-webpack-plugin', 
'clean-webpack-plugin', 
'webpack-dev-server', 
'css-loader', 
'webpack-merge', 
'style-loader', 
'babel-preset-env', 
'babel-loader', 
'babel-polyfill', 
'babel-preset-react'
Copy the code

and

'react',
'react-dom'
Copy the code

The first part only needs to be installed in the development environment (NPM I-D…). , the second part of the production environment is also installed (NPM I –save…) .

Scaffolding development can now be implemented using Node.

Let’s start with some useful and useful modules:

  • cross-spawn: a module to solve the problem of using NPM commands across platforms.
  • chalk: console color text output module.
  • fs-extra: a module that implements some file operations (such as recursive copy, delete, etc.) that are not included in the FS module.
  • commander: a module to preprocess incoming command line parameters.
  • validate-npm-package-name: module that validates the availability of project names entered by users.

First, introduce these basic modules into your code:

const spawn = require('cross-spawn'); const chalk = require('chalk'); const os = require('os'); const fs = require('fs-extra'); const path = require('path'); const commander = require('commander'); const validateProjectName = require('validate-npm-package-name'); const packageJson = require('.. /package.json');Copy the code

Then define our template copy function:

function copyTemplates() { try { if(! fs.existsSync(path.resolve(__dirname, '.. /templates'))) { console.log(chalk.red('Cannot find the template files ! ')); process.exit(1); } fs.copySync(path.resolve(__dirname, '.. /templates'), process.cwd()); console.log(chalk.green('Template files copied successfully! ')); return true; } catch(e) { console.log(chalk.red(`Error occured: ${e}`)) } }Copy the code

The FS module first checks if the template file exists (to prevent it from being deleted by the user), if it does, it copies it to the scaffold’s current working directory (process.cwd()) via FS’s copySync method, if not, an error message will appear, and then exits the process using exit code 1.

Then define the package.json handler;

Function generatePackageJson() {let packageJson = {name: projectName, version: '1.0.0', description: '', scripts: { start: 'webpack-dev-server --open --config webpack.dev.conf.js', build: 'webpack --config webpack.prod.conf.js' }, author: '', license: '' }; try { fs.writeFileSync(path.resolve(process.cwd(), 'package.json'), JSON.stringify(packageJson)); console.log(chalk.green('Package.json generated successfully! ')); } catch(e) { console.log(chalk.red(e)) } }Copy the code

It can be seen that a JavaScript Object is defined first, then the properties are modified, and its JSON string is written into the package. JSON file through the FS module, realizing the generation of package. JSON.

Install devDependencies and dependencies:

function installAll() { console.log(chalk.green('Start installing ... ')); let devDependencies = ['webpack', 'webpack-cli', 'html-webpack-plugin', 'clean-webpack-plugin', 'webpack-dev-server', 'css-loader', 'webpack-merge', 'style-loader', 'babel-preset-env', 'babel-loader', 'babel-polyfill', 'babel-preset-react']; let dependencies = ['react', 'react-dom']; const child = spawn('cnpm', ['install', '-D'].concat(devDependencies), { stdio: 'inherit' }); child.on('close', function(code) { if(code ! == 0) { console.log(chalk.red('Error occured while installing dependencies! ')); process.exit(1); } else { const child = spawn('cnpm', ['install', '--save'].concat(dependencies), { stdio: 'inherit' }) child.on('close', function(code) { if(code ! == 0) { console.log(chalk.red('Error occured while installing dependencies! ')); process.exit(1); } else { console.log(chalk.green('Installation completed successfully! ')); console.log(); console.log(chalk.green('Start the local server with : ')) console.log(); console.log(chalk.cyan(' npm run start')) console.log(); console.log(chalk.green('or build your app via :')); console.log(); console.log(chalk.cyan(' npm run build')); }}}})); }Copy the code

In the cross-spawn function, the CNPM setup command is executed. Note the configuration items:

{ 
    stdio: 'inherit' 
}
Copy the code

Means to connect the output pipe of the child process to the parent process, and the parent process can automatically accept the output of the child process, see options.stdio.

Preprocessing command line parameters through commander module;

const program = commander
.version(packageJson.version)
.usage(' [options]')
.arguments('<project-name>')
.action(name => {
    projectName = name;
})
.allowUnknownOption()
.parse(process.argv);
Copy the code

The version method defines the create-react-application -v output, the usage method defines the command line usage, the arguments define the default arguments accepted by the program, and the action function callback handles the default arguments. AllowUnknownOption accepts extra arguments and parse parses extra unparsed arguments to process.argv.

Finally, three methods are called to implement the React development environment setup:

if(projectName == undefined) { console.log(chalk.red('Please pass the project name while using create-react! ')); console.log(chalk.green('for example:')) console.log(); console.log(' create-react-application ' + chalk.yellow('<react-app>')); } else { const validateResult = validateProjectName(projectName); if(validateResult.validForNewPackages) { copyTemplates(); generatePackageJson(); installAll(); //console.log(chalk.green(`Congratulations! React app has been created successfully in ${process.cwd()}`)); } else { console.log(chalk.red('The project name given is invalid! ')); process.exit(1); }}Copy the code

If the accepted project name is empty, a warning will pop up. If not, verify that the project name is available. If not, issue a warning and exit the process. Otherwise, call the three main functions defined earlier to complete the environment setup.

Until now, the way to use this program is still node xxx.js –parameters, we need to customize a command, and preferably upload the program to NPM for easy use.

Define your commands and publish the NPM package

The following steps are required to implement the custom command and publish the NPM module:

  • Modify the entry file by adding the following two sentences in the header:

    #! /usr/bin/env node 'use strict'Copy the code

    The second line must not be less!

  • Modify package.json by adding the bin property:

      // package.json
      {
          "bin": {
              "create-react-application": "package/create-react.js"
          }
      }
    Copy the code
  • Run the following command:

      npm link
    Copy the code
  • Register an NPM account (ignore it if already registered).

  • Run the following command:

      npm adduser
    Copy the code

    And enter the account password.

  • Run the following command:

      npm publish
    Copy the code

    Next you can receive a successful release email!

To update your NPM module, perform the following steps:

  • Update your version number with the following command:

      npm version x.x.x
    Copy the code
  • Then run the following command to publish;

      npm publish
    Copy the code

After completing the above steps, you can download your module from NPM.

Third, FQA

(1) About#! /usr/bin/env node

This is a way of writing Unix operating systems with names like Shebang, Hashbang, etc. According to Wikipedia, this line of code is written in a script so that when the operating system executes the script as an executable, it will find the corresponding program (such as Node in this article), and the code itself will be ignored by the interpreter.

(2) Aboutnpm link

Implementation of NPM Link is a two-step process, as explained in the official NPM documentation. When you use NPM link in your package, the global folder will be: {prefix}/lib/node_modules/ links to the folder where NPM link is executed, and also links all executables in the package where NPM link is executed to the global folder {prefix}/bin/{name}.

In addition, NPM link project-name links the globally installed project-name module to node_modules in the current folder where the NPM link command is executed.

According to the NPM documentation, the value of prefix can be:

  • /usr/local (on most systems)
  • %AppData%\ NPM (Windows)

For details, see Prefix Configuration and NPM Link

4. Make it simple

The scaffolding developed in this article has been uploaded to NPM and can be viewed in the following steps:

  • Install the create – react – application

      npm i -D create-react-application
    Copy the code

    or

      npm i -g create-react-application
    Copy the code
  • Using the create – react – application

      create-react-application <project-name>
    Copy the code

The source code has been uploaded to GitHub, welcome to join us (# manual funny).

In addition, there are many shortcomings in the article, such as the explanation of NPM link I am not very clear, welcome to add your comments!

5. Refer to the article

  • NPM Link command function analysis
  • prefix configuration
  • npm link
  • Build React development environment based on Webpack
  • Explore create-react-app source code
  • NPM release packages