美文网首页
了解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