首页 > 其他分享 >前端开发npm start的引导过程

前端开发npm start的引导过程

时间:2022-12-05 22:12:59浏览次数:43  
标签:npm const process require react start scripts 前端开发

以react初始化项目为例:

git clone [email protected]:geektcp/react-init.git

 

package.json的内容如下:

{
  "name": "react-init",
  "version": "0.1.0",
  "private": true,
  "dependencies": {
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^13.5.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4"
  },
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    "test": "react-scripts test",
    "eject": "react-scripts eject"
  },
  "eslintConfig": {
    "extends": [
      "react-app",
      "react-app/jest"
    ]
  },
  "browserslist": {
    "production": [
      ">0.2%",
      "not dead",
      "not op_mini all"
    ],
    "development": [
      "last 1 chrome version",
      "last 1 firefox version",
      "last 1 safari version"
    ]
  }
}

npm start其实是一个系统级别的命令,开发人员需要安装npm 并配置好环境变量。

这个命令可以理解为一个shell脚本,进入当前目录的package.json中找到start对应的脚本并执行。把package.json中start对应脚本换成任意脚本或者命令都可以直接执行。

这里是对应的脚本是:

react-scripts start
react-scripts其实是项目目录下一个文件,具体路径是:./node_modules/react-scripts,内容如下:
#!/usr/bin/env node
/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

'use strict';

// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
  throw err;
});

const spawn = require('react-dev-utils/crossSpawn');
const args = process.argv.slice(2);

const scriptIndex = args.findIndex(
  x => x === 'build' || x === 'eject' || x === 'start' || x === 'test'
);
const script = scriptIndex === -1 ? args[0] : args[scriptIndex];
const nodeArgs = scriptIndex > 0 ? args.slice(0, scriptIndex) : [];

if (['build', 'eject', 'start', 'test'].includes(script)) {
  const result = spawn.sync(
    process.execPath,
    nodeArgs
      .concat(require.resolve('../scripts/' + script))
      .concat(args.slice(scriptIndex + 1)),
    { stdio: 'inherit' }
  );
  if (result.signal) {
    if (result.signal === 'SIGKILL') {
      console.log(
        'The build failed because the process exited too early. ' +
          'This probably means the system ran out of memory or someone called ' +
          '`kill -9` on the process.'
      );
    } else if (result.signal === 'SIGTERM') {
      console.log(
        'The build failed because the process exited too early. ' +
          'Someone might have called `kill` or `killall`, or the system could ' +
          'be shutting down.'
      );
    }
    process.exit(1);
  }
  process.exit(result.status);
} else {
  console.log('Unknown script "' + script + '".');
  console.log('Perhaps you need to update react-scripts?');
  console.log(
    'See: https://facebook.github.io/create-react-app/docs/updating-to-new-releases'
  );
}
如上,见标注红色字体的部分,关键是spawn.sync这句,,其实就是执行一个js文件,
其路径为:./node_modules/react-scripts/scripts/start.js,内容如下:
// @remove-on-eject-begin
/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */
// @remove-on-eject-end
'use strict';

// Do this as the first thing so that any code reading it knows the right env.
process.env.BABEL_ENV = 'development';
process.env.NODE_ENV = 'development';

// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
// terminate the Node.js process with a non-zero exit code.
process.on('unhandledRejection', err => {
  throw err;
});

// Ensure environment variables are read.
require('../config/env');

const fs = require('fs');
const chalk = require('react-dev-utils/chalk');
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
const clearConsole = require('react-dev-utils/clearConsole');
const checkRequiredFiles = require('react-dev-utils/checkRequiredFiles');
const {
  choosePort,
  createCompiler,
  prepareProxy,
  prepareUrls,
} = require('react-dev-utils/WebpackDevServerUtils');
const openBrowser = require('react-dev-utils/openBrowser');
const semver = require('semver');
const paths = require('../config/paths');
const configFactory = require('../config/webpack.config');
const createDevServerConfig = require('../config/webpackDevServer.config');
const getClientEnvironment = require('../config/env');
const react = require(require.resolve('react', { paths: [paths.appPath] }));

const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));
const useYarn = fs.existsSync(paths.yarnLockFile);
const isInteractive = process.stdout.isTTY;

// Warn and crash if required files are missing
if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
  process.exit(1);
}

// Tools like Cloud9 rely on this.
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
const HOST = process.env.HOST || '0.0.0.0';

if (process.env.HOST) {
  console.log(
    chalk.cyan(
      `Attempting to bind to HOST environment variable: ${chalk.yellow(
        chalk.bold(process.env.HOST)
      )}`
    )
  );
  console.log(
    `If this was unintentional, check that you haven't mistakenly set it in your shell.`
  );
  console.log(
    `Learn more here: ${chalk.yellow('https://cra.link/advanced-config')}`
  );
  console.log();
}

// We require that you explicitly set browsers and do not fall back to
// browserslist defaults.
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
checkBrowsers(paths.appPath, isInteractive)
  .then(() => {
    // We attempt to use the default port but if it is busy, we offer the user to
    // run on a different port. `choosePort()` Promise resolves to the next free port.
    return choosePort(HOST, DEFAULT_PORT);
  })
  .then(port => {
    if (port == null) {
      // We have not found a port.
      return;
    }

    const config = configFactory('development');
    const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
    const appName = require(paths.appPackageJson).name;

    const useTypeScript = fs.existsSync(paths.appTsConfig);
    const urls = prepareUrls(
      protocol,
      HOST,
      port,
      paths.publicUrlOrPath.slice(0, -1)
    );
    // Create a webpack compiler that is configured with custom messages.
    const compiler = createCompiler({
      appName,
      config,
      urls,
      useYarn,
      useTypeScript,
      webpack,
    });
    // Load proxy config
    const proxySetting = require(paths.appPackageJson).proxy;
    const proxyConfig = prepareProxy(
      proxySetting,
      paths.appPublic,
      paths.publicUrlOrPath
    );
    // Serve webpack assets generated by the compiler over a web server.
    const serverConfig = {
      ...createDevServerConfig(proxyConfig, urls.lanUrlForConfig),
      host: HOST,
      port,
    };
    const devServer = new WebpackDevServer(serverConfig, compiler);
    // Launch WebpackDevServer.
    devServer.startCallback(() => {
      if (isInteractive) {
        clearConsole();
      }

      if (env.raw.FAST_REFRESH && semver.lt(react.version, '16.10.0')) {
        console.log(
          chalk.yellow(
            `Fast Refresh requires React 16.10 or higher. You are using React ${react.version}.`
          )
        );
      }

      console.log(chalk.cyan('Starting the development server...\n'));
      openBrowser(urls.localUrlForBrowser);
    });

    ['SIGINT', 'SIGTERM'].forEach(function (sig) {
      process.on(sig, function () {
        devServer.close();
        process.exit();
      });
    });

    if (process.env.CI !== 'true') {
      // Gracefully exit when stdin ends
      process.stdin.on('end', function () {
        devServer.close();
        process.exit();
      });
    }
  })
  .catch(err => {
    if (err && err.message) {
      console.log(err.message);
    }
    process.exit(1);
  });

 

这部分最关键的是这句:

 const devServer = new WebpackDevServer(serverConfig, compiler);
    // Launch WebpackDevServer.
    devServer.startCallback(() => {
      if (isInteractive) {
        clearConsole();
      }

就是new一个WebpackDevServer服务器,类似启动一个nginx服务器一样,启动一个web服务器。

 

总结一下npm start的引导过程:

npm start  

-> ./node_modules/react-scripts/bin/react-scripts start

-> ./node_modules/react-scripts/scripts/start.js

-> (new WebpackDevServer (serverConfig,compiler)).startCallback



 

标签:npm,const,process,require,react,start,scripts,前端开发
From: https://www.cnblogs.com/geektcp/p/16953694.html

相关文章

  • application [ROOT] appears to have started a thread named [xxxx] but has failed
    在IDEA上运行工程后,报错,查看相关资料,原因是包缺失解决:1.根据IDEA的提示,发现有好多包引入有误或引入正确,但提示引入失败2.更新build.gradle中包,等待下载完成后再运行,问......
  • web前端开发:JavaScript网页脚本语言
    目录JavaScript网页脚本语言一、JavaScript简介1.注释语法2.引入JS的方式(1)head内script标签内编写(2)head内script标签src属性引入外部JS资源(3)body内最底部通过script标签src......
  • 前端开发:4、JavaScript简介、变量与常量、数据类型及内置方法、运算符、流程控制、循
    前端开发之JavaScript目录前端开发之JavaScript一、JavaScript简介二、JS基础三、变量与常量四、基本数据类型1、数值类型2、字符类型3、布尔类型五、特殊数据类型1、nu......
  • 前端开发之js
    目录前端开发之js今日内容概要今日内容详细JS简介JS基础变量与常量基本数据类型运算符流程控制函数内置对象作业前端开发之js今日内容概要JS简介JS基础变量与常量基......
  • Angular 复习与进阶系列 – Get Started
    前言这一篇主要是教一些基础中的基础,方便我后续讲解其它主题的时候,可以列出一些samplecode. BeforeStart开始前,我们需要知道几个小知识1.AngularCompilat......
  • 前端开发(05)
    目录JS简介JS基础变量与常量基本数据类型数值(Number)布尔类型(boolean)未定义类型(undefined)null(空类型)null和undefined区别:数字类型字符串类型检测数据类型通过typ......
  • cnpm : 无法加载文件 C:\Users\Administrator\AppData\Roaming\npm\cnpm.ps1,因
    set-ExecutionPolicyRemoteSigned......
  • 精选、前端开发N个必备的 VSCode 插件
    目录​​一、汉化vscode​​​​二、vue2代码提示​​​​三、格式化高亮vue代码​​​​四、实时预览网页效果​​​​五、html标签​​​​六、格式化代码​​​​七、规......
  • npm 介绍
    我们需要安装node.js,安装后就自带有npm了,网址:https://nodejs.org/en/可以安装稳定版本,也可以安装最新版本 随后打开终端,win+r,输入cmd,输入:npm-v查看版本......
  • Web前端开发中的MCRV模式
     摘要针对前端开发中基于ajax的复杂页面开发所面临的代码规模大,难以组织和维护,代码复用性、扩展性和适应性差等问题,本文尝试以MVC思想为基础,结合Web前端开发中“内容......