前言:
- 本来一直是知道create-react-app可以命令初始化项目,因此就想让我自己的脚手架也能达到这个目标,自己的实现计划如下:
- 希望将脚手架放在npm上,成为可以安装的依赖包;
- 然后希望可以实现和create-react-app一样的方式来初始化一个react项目,有如下三种让方式:
`npx create-react-app my-app`
`npm init react-app my-app` // 拓展:如果是项目目录,一定会存在一个package.json文件
`yarn create react-app my-app`
// 以上可以理解为等价于以下两个步骤,create-react-app可以作为命令,然后执行其内部一系列代码
// yarn global add create-react-app
// create-react-app my-app
-
然后自己实现了如何将一个项目发布到npm上面(24小时内可以删除
npm unpublish [npm package] --force
,超过则不能删除)。
脑子想到的问题:
执行create-react-app my-app
后,是怎样创建了my-app项目目录,并是怎样将自己搭建好的脚手架项目克隆下来到my app文件里的(当时是这样想的,其实真正的实现并不是这样子的) -
然后后面我找到了一个文档(深度解析
create-react-app
源码),是阐述create-react-app命令初始化项目的源码,看了之后,就想着只要理解了初始化项目的原理就行了,自己实现这个功能太麻烦了。
如下是create-react-app命令包的一些依赖,后期可以不断学习了解这些包:
"dependencies": {
"chalk": "2.4.2", // 这个库的作用是改变命令行中输出信息的样式,颜色等
"commander": "2.20.0", // Node命令接口,也就是可以用它代管Node命令
"cross-spawn": "6.0.5", // 用来执行node进程
"envinfo": "7.3.1", // 可以打印当前操作系统的环境和指定包的信息
"fs-extra": "7.0.1", // 外部依赖,Node自带文件模块的外部扩展模块
"hyperquest": "2.1.3", // 这个用于将http请求流媒体传输
"inquirer": "6.5.0",
"semver": "6.3.0", // 用于比较Node版本
"tar-pack": "3.4.1",
"tmp": "0.0.33",
"validate-npm-package-name": "3.0.0" // 检查包名是否合法
}
// 还有其他node的api
`child_process`
execSync:引用自child_process.execSync,用于执行需要执行的子进程
总结:
- 自己之前认识上的误区更正:
(1)create-react-app放在npm上的git地址就是这个大包的地址,并不是自身脚手架的地址。
(2)create-react-app my-app
初始化的项目,脚手架真正的内部文件什么的,都是通过react-scripts里面的模板添加进去的,即重点是react-scripts文件包。 - 重点都在react-scripts这个文件夹下面,对这个文件夹做了很多的处理,估计后面我没事了还要多看看。
-
create-react-app my-app
初始化项目后,通过针对输入的name(my-app
)以及其他的参数进行判断和函数的执行,再到将react-script
里的package.json
和template
添加进my-app
项目中,再进行install
安装依赖,即完成。
create-react-app是如何统一更新第三方依赖包:
实现:只需要更新react-script
这个包即可,查看(react-scripts版本)。不过前提是项目没有进行npm run eject
。
// 比如,将当前版本升级到3.1.0:
`yarn add --exact react-scripts@3.1.0`
`npm install --save --save-exact react-scripts@3.1.0`
原因:
(1)首先,没有eject之前,项目package.json中除了react、react-dom、react-script依赖外,没有其他的依赖包;
// eject前
{
"name": "test-my-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"react": "^16.9.0",
"react-dom": "^16.9.0",
"react-scripts": "3.1.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
}
}
// eject后
{
"name": "my-app",
"version": "0.1.0",
"private": true,
"dependencies": {
"@babel/core": "7.2.2",
"@svgr/webpack": "4.1.0",
"babel-core": "7.0.0-bridge.0",
"babel-eslint": "9.0.0",
"babel-jest": "23.6.0",
"babel-loader": "8.0.5",
"babel-plugin-named-asset-import": "^0.3.1",
"babel-preset-react-app": "^7.0.2",
"bfj": "6.1.1",
"case-sensitive-paths-webpack-plugin": "2.2.0",
"css-loader": "1.0.0",
"dotenv": "6.0.0",
"dotenv-expand": "4.2.0",
"eslint": "5.12.0",
"eslint-config-react-app": "^3.0.8",
"eslint-loader": "2.1.1",
"eslint-plugin-flowtype": "2.50.1",
"eslint-plugin-import": "2.14.0",
"eslint-plugin-jsx-a11y": "6.1.2",
"eslint-plugin-react": "7.12.4",
"file-loader": "2.0.0",
"fs-extra": "7.0.1",
"html-webpack-plugin": "4.0.0-alpha.2",
"identity-obj-proxy": "3.0.0",
"jest": "23.6.0",
"jest-pnp-resolver": "1.0.2",
"jest-resolve": "23.6.0",
"jest-watch-typeahead": "^0.2.1",
"mini-css-extract-plugin": "0.5.0",
"optimize-css-assets-webpack-plugin": "5.0.1",
"pnp-webpack-plugin": "1.2.1",
"postcss-flexbugs-fixes": "4.1.0",
"postcss-loader": "3.0.0",
"postcss-preset-env": "6.5.0",
"postcss-safe-parser": "4.0.1",
"react": "^16.8.6",
"react-app-polyfill": "^0.2.2",
"react-dev-utils": "^8.0.0",
"react-dom": "^16.8.6",
"resolve": "1.10.0",
"sass-loader": "7.1.0",
"style-loader": "0.23.1",
"terser-webpack-plugin": "1.2.2",
"url-loader": "1.1.2",
"webpack": "4.28.3",
"webpack-dev-server": "3.1.14",
"webpack-manifest-plugin": "2.0.4",
"workbox-webpack-plugin": "3.6.3"
},
"scripts": {
"start": "node scripts/start.js",
"build": "node scripts/build.js",
"test": "node scripts/test.js"
},
"eslintConfig": {
"extends": "react-app"
},
"browserslist": [
">0.2%",
"not dead",
"not ie <= 11",
"not op_mini all"
],
"jest": {
"collectCoverageFrom": [
"src/**/*.{js,jsx,ts,tsx}",
"!src/**/*.d.ts"
],
"resolver": "jest-pnp-resolver",
"setupFiles": [
"react-app-polyfill/jsdom"
],
"testMatch": [
"<rootDir>/src/**/__tests__/**/*.{js,jsx,ts,tsx}",
"<rootDir>/src/**/?(*.)(spec|test).{js,jsx,ts,tsx}"
],
"testEnvironment": "jsdom",
"testURL": "http://localhost",
"transform": {
"^.+\\.(js|jsx|ts|tsx)$": "<rootDir>/node_modules/babel-jest",
"^.+\\.css$": "<rootDir>/config/jest/cssTransform.js",
"^(?!.*\\.(js|jsx|ts|tsx|css|json)$)": "<rootDir>/config/jest/fileTransform.js"
},
"transformIgnorePatterns": [
"[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$",
"^.+\\.module\\.(css|sass|scss)$"
],
"moduleNameMapper": {
"^react-native$": "react-native-web",
"^.+\\.module\\.(css|sass|scss)$": "identity-obj-proxy"
},
"moduleFileExtensions": [
"web.js",
"js",
"web.ts",
"ts",
"web.tsx",
"tsx",
"json",
"web.jsx",
"jsx",
"node"
],
"watchPlugins": [
"/Users/jojo/learn-code/my-app/node_modules/jest-watch-typeahead/filename.js",
"/Users/jojo/learn-code/my-app/node_modules/jest-watch-typeahead/testname.js"
]
},
"babel": {
"presets": [
"react-app"
]
}
}
(2)其次,webpack的配置也没有出现,确保了后面更新依赖包后,eject后,webpack配置也会随之更新。
eject前
eject后
ok,终于解决了我的疑问!!!
PS说明:
create-react-app大包git地址:https://github.com/facebook/create-react-app
包含的两个重要的包:
网友评论