likes
comments
collection
share

create-react-app build 命令源码解析

作者站长头像
站长
· 阅读数 44

准备工作

调试 cra build 源码步骤

  1. 打开源文件输入 debugger
  2. 点击 package.json 里 scripts 上的 debug 按钮, 选择 build。 (有很多方式,不一一列举)

create-react-app build 命令源码解析

create-react-app build 命令源码解析

入口文件 react-scripts.js

const args = process.argv.slice(2); // react-scripts build

process.argv 第一个是 node 可执行命令路径, 第二个是当前执行的文件, 第三个才是命令行参数 build, 如下。

1. '/Users/xxx/.nvm/versions/node/v18.12.1/bin/node', 
2. '/Users/xxx/workspace/cra/node_modules/.bin/react-scripts'
3. 'build'

1. 读取用户命令行参数,找到对应执行文件

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

if (['build', 'eject', 'start', 'test'].includes(script)) {
  const result = spawn.sync(
    process.execPath, // Node.js 进程的可执行文件的绝对路径名
    nodeArgs 
      .concat(require.resolve('../scripts/' + script))
      .concat(args.slice(scriptIndex + 1)),
    { stdio: 'inherit' } 
  );
}

spawn.sync(xxxx) 代码其实就是执行 ../scripts/build.js 文件, 如下。 node "User/xxx/cra/node_modules/react-scripts/scripts/build.js"

核心代码 build.js

2. 加载环境变量, 执行打包命令

process.env.BABEL_ENV = 'production';
process.env.NODE_ENV = 'production';
// 设置环境变量

require('../config/env'); 
// 注入环境变量。下一节详解

const config = configFactory('production');
// configFactory 就是 webpack.config.js。里面有 cra 帮我们写好的 webpack 配置

fs.emptyDirSync(paths.appBuild); 
// 清空 build 目录
    
copyPublicFolder()

build(previousFileSizes);
  
function build() {
  const compiler = webpack(config); // 生成 compiler
  return new Promise((resolve, reject) => {
    compiler.run((err, stats) => { // 调用 compiler.run 方法开始打包
      // do something
    });
  });
}
  1. 声明当前环境变量 production
  2. 注入 .env 文件变量
  3. configFactory 函数返回配置好的 webpack.config 配置文件
  4. 每次打包都清空 build 目录
  5. copyPublicFolder 函数把 cra 的 public 目录下的除了 index.html 外的所有文件迁移到打包的生成的 build 目录中, 在这里大家可能会有疑问。为什么排除index.html, 因为 index.html 是在 webpack.config.js 里用 html-webpack-plugin 生成的
  6. webpack(config) 获取 compiler。compiler.run 方法调用就会开启 webpack 打包。

补充工作

3. 注入环境变量 env.js

const dotenvFiles = [
  `${paths.dotenv}.${NODE_ENV}.local`,
  NODE_ENV !== 'test' && `${paths.dotenv}.local`,
  `${paths.dotenv}.${NODE_ENV}`,
  paths.dotenv,
].filter(Boolean);

dotenvFiles.forEach(dotenvFile => {
  if (fs.existsSync(dotenvFile)) {
    require('dotenv-expand')(
      require('dotenv').config({
        path: dotenvFile,
      })
    );
  }
});

env文件加载也有优先级, 其顺序如下, 越靠前优先级越高

1. .env.(development|production).local  
2. .env.local  
3. .env.(development|production)  
4. .env 

4. 设置 NODE_PATH

const appDirectory = fs.realpathSync(process.cwd());
process.env.NODE_PATH = (process.env.NODE_PATH || '')
  .split(path.delimiter) 
  .filter(folder => folder && !path.isAbsolute(folder))
  .map(folder => path.resolve(appDirectory, folder))
  .join(path.delimiter);
  1. process.env.NODE_PATH 指定模块搜索路径。
  2. path.delimiter window下是;符号 mac下是:符号

核心代码都在这里了, 大家如果对一些方法感兴趣的话可自行去源码中查看。

总结

看源码只是为了空闲时学习, 方便以后自己遇到类似的需求时可以有思路。

相关文章

create-react-app start 命令源码解析

文档参考

cra 官方文档: create-react-app cra github: create-react-app

转载自:https://juejin.cn/post/7174797203725090877
评论
请登录