美文网首页
了解create-react-app初始化脚手架的原理

了解create-react-app初始化脚手架的原理

作者: codingQi | 来源:发表于2019-08-13 20:08 被阅读0次

前言:

  1. 本来一直是知道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
  1. 然后自己实现了如何将一个项目发布到npm上面(24小时内可以删除npm unpublish [npm package] --force,超过则不能删除)。
    脑子想到的问题:
    执行create-react-app my-app后,是怎样创建了my-app项目目录,并是怎样将自己搭建好的脚手架项目克隆下来到my app文件里的(当时是这样想的,其实真正的实现并不是这样子的)

  2. 然后后面我找到了一个文档(深度解析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.jsontemplate添加进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
包含的两个重要的包:

相关文章

网友评论

      本文标题:了解create-react-app初始化脚手架的原理

      本文链接:https://www.haomeiwen.com/subject/umpbjctx.html