准备工作
调试 cra start 命令源码步骤
- 打开源文件输入 debugger
- 点击 package.json 里 scripts 上的 debug 按钮, 选择 start。 (有很多方式,不一一列举)
入口文件 react-scripts.js
const args = process.argv.slice(2); // react-scripts start
process.argv 第一个是 node 可执行命令路径, 第二个是当前执行的文件, 第三个才是命令行参数 start, 如下。
1. '/Users/xxx/.nvm/versions/node/v18.12.1/bin/node',
2. '/Users/xxx/workspace/cra/node_modules/.bin/react-scripts'
3. 'start'
1. 读取用户命令行参数,找到对应执行文件
const scriptIndex = args.findIndex(
x => x === 'build' || x === 'eject' || x === 'start' || x === 'test'
); // 0
const script = scriptIndex === -1 ? args[0] : args[scriptIndex]; // start
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/start.js 文件, 如下。
node "User/xxx/cra/node_modules/react-scripts/scripts/start.js"
核心代码
进入 start.js
process.env.BABEL_ENV = 'development';
process.env.NODE_ENV = 'development';
// 设置环境变量为开发环境变量
require('../config/env');
// 加载 .env 文件。具体内容在上一篇 build 命令源码里有讲
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
const HOST = process.env.HOST || '0.0.0.0';
// 定义默认端口跟域名
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
checkBrowsers(paths.appPath, isInteractive)
.then(() => {
// 检查端口是否被占用
return choosePort(HOST, DEFAULT_PORT);
})
.then(port => {
if (port == null) {
return;
}
const config = configFactory('development');
// configFactory 就是 webpack.config.js。里面有 cra 帮我们写好的 webpack 配置
const appName = require(paths.appPackageJson).name;
// 获取 cra 创建出来的项目的 package.json 里的 name 值
const useTypeScript = fs.existsSync(paths.appTsConfig);
// 查看项目是否有 tsconfig.json
const compiler = createCompiler({
appName,
config,
urls,
useYarn,
useTypeScript,
webpack,
});
// 生成 compiler
const serverConfig = {
...createDevServerConfig(proxyConfig, urls.lanUrlForConfig),
host: HOST,
port,
};
// 生成 webpack-dev-server 配置
const devServer = new WebpackDevServer(serverConfig, compiler);
// webpack-dev-server 是个 class 类, 它会帮我们启动一个 http 服务器, 具体 api 可以看文档
devServer.startCallback(() => {
if (isInteractive) { //
clearConsole(); // // 看标准输出流是否连接到终端, 如果连接, 清空终端日志
}
openBrowser(urls.localUrlForBrowser);
});
// 启动服务, 启动之后打开浏览器
})
核心代码都在这里了, 大家如果对一些方法感兴趣的话可自行去源码中查看, 代码还是很简单的。
总结
用一句话概括 start 命令做了什么。就是生成 compiler, 用 webpack-dev-server 启动 http 服务器来访问项目。
相关文章
文档参考
cra 官方文档: create-react-app
cra github: create-react-app
webpack-dev-server github: webpack-dev-server