Recently I have read the source code of [email protected] and create-React-app. As [email protected] is now officially recommended, which is a big change, so I won’t write about vue-cli (it is said that the operation of [email protected] is a little too complicated to create the project, so Yuyuxi greatly borrowed the idea of create-React-app. Made a zero configuration [email protected], interested partners can go to their own ha). This article only explains the implementation of create-React-app. However, since create-React-app source code plus comments total more than 800 lines of code, it is not intended to read its source code one by one. If you want to read all the source code, you can first read this article, and then go to see the source code. It should be a lot easier to understand.

With all this nonsense, it’s time to get down to business. So what’s the real deal with Create-React-app? Here’s the first sentence of the official readME file:

Create React apps with no build configuration.
Copy the code

Well, that makes it pretty clear: Creact-React-app lets you create a React app with zero configuration! Why the emphasis on zero configuration? As we all know, React is a modular, componentized framework, which requires webPack configuration, right? Also, with JSX and the new features of ES6, you need to configure Babel. Another thing you need to check for code style is esLint? It will probably take a day or two for a novice to successfully configure an environment that can run React. So the significance of zero configuration is that xiao Moxin can quickly write his first React-hello-world without knowing configuration, which is very fulfilling!

It doesn’t matter if you haven’t used create-react-app before, here’s its simplest use:

create-react-app my-app
Copy the code

Wait a few minutes to create a my-app project in the current directory, then go to the root directory NPM start to launch a React project. Remember to install the Create-react-app globally first.

Introduces what create-React-app is and its simplest use. Now let’s work on a create-React-app clone. Because we are implementing a simplified version, removing the functions of environment checking, version checking, offline package installation and so on, leaving about 100 lines of code, which is called simple-creation-React-app for the time being.

Before implementing the code, let’s look at the following ideas:

  1. throughcommanderGet the name of the project;
  2. If the project name is empty (in fact, you need to check the validity of the package name, which will be ignored here), exit the process and prompt the user that the project name cannot be empty, otherwise go to Step 3;
  3. Create a subdirectory under the current directory, the directory name is the user input project name, and initialize one insidepackage.jsonFile;
  4. Go to the project’s root directory and installreact.react-domreact-scriptsThree dependencies;
  5. When the dependency installation is complete, callreact-scriptstheinitMethod initializes the project (mainly the copy template)
  6. The end;

Follow the above idea and start coding!

I’ll introduce some of the necessary dependencies, but I won’t expand on what they do. And define a variable called projectName to hold the projectName:

const commander = require('commander');
const chalk = require('chalk');
const spawn = require('cross-spawn'); 
const fs = require('fs-extra');
const path = require('path');
const os = require('os');

const packageJson = require('./package.json');

letprojectName; // Project name, which is obtained as a command-line argumentCopy the code

Next, you create an instance of Commander, take the project name the user entered, and determine if it is empty. If it is empty, the user is prompted and the process exits.

const program = new commander.Command(packageJson.name)
.version(packageJson.version)
.arguments('<project-directory>')
.usage(`${chalk.green('<project-directory>')}[options]`) .action(name => { projectName = name; }).parse(process.argv) // Format the arguments, as required // If no project name is entered, a prompt is given and the process exitsif(typeof projectName === 'undefined') {
  console.error('please specify the project directory');
  console.log();
  console.log('For examaple: ')
  console.log(`    ${chalk.cyan(program.name())} ${chalk.green('my-react-app')}`)
  console.log();
  process.exit(1);
}
Copy the code

If the project name is not empty, start creating an empty project and initialize a packgae.json file:

CreateApp (projectName);functioncreateApp(name) { const root = path.resolve(name); fs.ensureDirSync(root); Console. log(' Creating a new React appin ${chalk.green(root)}. `); // Create new project package.json const packageJson = {name: name, version:'0.1.0 from',
    private: true
  };
  fs.writeFileSync(path.join(root, 'package.json'), JSON.stringify(packageJson, null, 2) + os.EOL); // Save the path of the current directory. Const originalDirectory = process.cwd(); // Enter the newly created project in process.chdir(root); run(root, originalDirectory); }Copy the code

After creating a new project, go through process.chdir(root); Enter the working directory of the process into the new project. After a few minutes, when the dependencies are installed, start calling react-scripts (which is a submodule of the create-React-app, It contains the init method for loading other plugins for your project, parsing the final WebPack configuration (also not expanded here, you can click here) and initializing the project (mainly copying the template into the new project) :

function run(root, originalDirectory) {
  const allDependencies = ['react'.'react-dom'.'react-scripts'];
  console.log('Installing packages. This migth take a couple of minutes... ');
  console.log(`Installing ${chalk.cyan('react')}.${chalk.cyan('react-dom')}, and ${chalk.cyan('react-scripts')}. `); console.log(); install(root, allDependencies) .then(() => { console.log(); console.log('Installing is success! '); console.log(); Const scriptsPath = path.resolve(process.cwd(), const scriptsPath = path.resolve(),'node_modules'.'react-scripts'.'scripts'.'init.js'
    )
    const init  = require(scriptsPath);
    init(root, projectName, null, originalDirectory);
  })
  .catch(reason => {
    console.log();
    console.log('Aborting installation.');
    if(reason.command) {
      console.log(`    ${chalk.cyan(reason.command)} has failed.`);
    } else {
      console.log(chalk.red('Unexpected error! '), reason); }})} // Install the NPM dependency in the specified directoryfunction install(root, dependencies) {
  return new Promise((resolve, reject) => {
    let command = 'yarnpkg';
    const args = ['add'];
    [].push.apply(args, dependencies);
    let child = spawn(command, args, {stido: 'inherit'});
    child.on('close', code => {
      if(code ! == 0) { reject({command: `${command} ${args.join(' ')}`});return; } resolve(); })}); }Copy the code

After counting, there are more than 100 lines of code in total, which is the core function of create-React-app. Of course, in fact, there are environmental detection, version detection, offline installation, etc., we ignored here, if interested, you can have a look at the official source code.

Create-reate-app: Create-reate-app: Create-reate-app: Create-reate-app: Create-reate-app: Create-reate-app