分析React和Vue脚手架
# 分析React和Vue脚手架
# React脚手架
创建一个React应用:
create-react-app react_app
查看package.json
中的脚本:
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
可以看到使用的是React封装的库react-scripts
来运行项目的。
打开node_modules/.bin/react-scripts
脚本,可看到执行的是/react-scripts/bin/react-scripts.js
文件,查看核心代码:
// ...
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' }
);
// ...
}
// ...
上面的代码很简单,如果执行的脚本是['build', 'eject', 'start', 'test']
中的一个,就创建子进程去scripts/
目录下执行对应的文件。
简单分析执行npm run dev
的情况,执行scripts/start.js
:
process.env.BABEL_ENV = 'development';
process.env.NODE_ENV = 'development';
process.on('unhandledRejection', err => {
throw err;
});
// Ensure environment variables are read.
require('../config/env');
// ...
// Tools like Cloud9 rely on this.
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000; // 默认端口3000
const HOST = process.env.HOST || '0.0.0.0';
// ...
// We require that you explicitly set browsers and do not fall back to
// browserslist defaults.
const { checkBrowsers } = require('react-dev-utils/browsersHelper');
// 检测浏览器设置,没有则降级至browserslist中默认配置
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;
}
// 生成webpack的配置文件
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({
// createCompiler -> compiler = webpack(config) 创建compiler
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,
};
// 创建devServer
const devServer = new WebpackDevServer(serverConfig, compiler);
// Launch WebpackDevServer.
devServer.startCallback(() => {
// ...
openBrowser(urls.localUrlForBrowser);
});
// ...
})
.catch(err => {
if (err && err.message) {
console.log(err.message);
}
process.exit(1);
});
做了三件事件:
生成各项配置,最主要通过
configFactory
工厂函数来生成Webpack的配置通过内部封装的createCompiler函数创建Compiler
创建DevServer
configFactory
工厂函数目的就是生成Webpack Config,涉及点详见react-scripts中的webpack.config.js
文件
# Vue脚手架
编辑 (opens new window)
上次更新: 2022/06/30, 22:20:12