cisen / blog

Time waits for no one.
132 stars 20 forks source link

create-react-app相关 #120

Open cisen opened 5 years ago

cisen commented 5 years ago

使用webpack

项目 eject

使用 CRA 创建完项目以后,项目在package.json里面提供了这样一个命令:

"eject": "react-scripts eject"

执行完这个命令——yarn run eject后会将封装在 CRA 中的配置全部反编译到当前项目,这样用户就可以完全取得 webpack 文件的控制权,想怎么修改就怎么修改了。

# eject 后项目根目录下会出现 config 文件夹,里面就包含了 webpack 配置
config
├── env.js
├── jest
│   ├── cssTransform.js
│   └── fileTransform.js
├── paths.js
├── polyfills.js
├── webpack.config.dev.js // 开发环境配置
├── webpack.config.prod.js // 生产环境配置
└── webpackDevServer.config.js

CRA 与其他脚手架不同的另一个地方,就是可以通过升级其中的react-scripts包来升级 CRA 的特性。比如用老版本 CRA 创建了一个项目,这个项目不具备 PWA 功能,但只要项目升级了react-scripts包的版本就可以具备 PWA 的功能,项目本身的代码不需要做任何修改。

但如果我们使用了eject命令,就再也享受不到 CRA 升级带来的好处了,因为react-scripts已经是以文件的形式存在于你的项目,而不是以包的形式,所以无法对其升级。

替换 react-scripts 包

react-scripts 是 CRA 的一个核心包,一些脚本和工具的默认配置都集成在里面,使用 CRA 创建项目默认就是使用这个包,但是 CRA 还提供了另外一种方式来创建 CRA 项目,即使用自定义 scripts 包的方式。

# 默认方式
$ create-react-app foo
# 自定义 scripts 包方式
$ create-react-app foo --scripts-version 自定义包

自定义包可以是下面几种形式:

自定义 scripts 包的结构可以参照react-scripts包的结构,只要修改对应的 webpack 配置文件,并安装上所需的 webpack loader 或 plugin 包就可以了。

使用 react-app-rewired

虽然有这两种方式可以扩展 webpack 配置,但是很多开发者还是觉得太麻烦,有没有一种方式可以既不用eject项目又不用创建自己的 scripts 包呢?答案是肯定的,react-app-rewired 是 react 社区开源的一个修改 CRA 配置的工具。

在 CRA 创建的项目中安装了react-app-rewired后,可以通过创建一个config-overrides.js文件来对 webpack 配置进行扩展。

/* config-overrides.js */
module.exports = function override(config, env) {
//do stuff with the webpack config...
return config;
}

override方法的第一个参数config就是 webpack 的配置,在这个方法里面,我们可以对 config 进行扩展,比如安装其他 loader 或者 plugins,最后再将这个 config 对象返回回去。

最后再修改package.json中的脚本命令,修改内容请见这里

scripts 包 + override 组合

虽然react-app-rewired的方式已经可以很方便地修改 webpack 的配置了,但其实我们也可以在自定义的 script 包中实现类似的功能。

在react-app-rewired的源码中可以看到它核心的包也叫 react-app-rewired,里面重新覆盖了react-scripts中的几个脚本文件,包括build.js、start.js和test.js。

具体过程是怎样的呢?以build.js为例:

先获取 webpack 的基本配置,然后再调用config-overrides.js(就是在根目录中新增的那个文件)中的override方法,将原先的 webpack 对象作为参数传入, 再取得经过修改后的 webpack 配置对象 最后再调用react-scripts中的build.js脚本,传入修改后的 webpack 对象来执行命令, 具体源码如下:


const overrides = require('../config-overrides');
const webpackConfigPath = paths.scriptVersion + "/config/webpack.config.prod";
// load original config
const webpackConfig = require(webpackConfigPath);
// override config in memory
require.cache[require.resolve(webpackConfigPath)].exports =
overrides.webpack(webpackConfig, process.env.NODE_ENV);
// run original script
require(paths.scriptVersion + '/scripts/build');

知道了原理之后,我们也可以修改自定义 scripts 包的脚本文件,还是以build.js为例,在获取基本 webpack 配置对象和使用 webpack 对象之间加入以下代码:

// override config
const override = require(paths.configOverrides);
const overrideFn = override || ((config, env) => config);
const overrideConfig = overrideFn(config, process.env.NODE_ENV);

overrideConfig就是修改后的 webpack 对象,最后修改调用了 webpack 对象的代码,将原来的 webpack 对象替换成修改后的 webpack 对象。

支持flow

安装babel/preset-flow,https://babeljs.io/docs/en/babel-preset-flow

支持typescript

1. 添加类型

要使用 TypeScript 启动新的 Create React App 项目,你可以运行:

$ npx create-react-app my-app --typescript
$ # 或者
$ yarn create react-app my-app --typescript

要将 TypeScript 添加到 Create React App 项目,请先安装它:

$ npm install --save typescript @types/node @types/react @types/react-dom @types/jest
$ # 或者
$ yarn add typescript @types/node @types/react @types/react-dom @types/jest

接下来,将任何文件重命名为 TypeScript 文件(例如 src/index.js 重命名为 src/index.tsx )并 重新启动开发服务器!

类型错误将显示在与构建错误相同的控制台中。

要了解有关 TypeScript 的更多信息,请查看 其文档 https://facebook.github.io/create-react-app/docs/adding-typescript

2. 添加babel插件

在preset添加@babel/plugin-transform-typescript https://babeljs.io/docs/en/babel-preset-typescript

其他用法

添加alias别名

在webpack.config.js里面搜索alias 然后

'react-three-fiber': path.resolve(__dirname, '../src/react-three-fiber'),

禁止eslint

在webpack.config.js里面,把下面这句给注释掉

{
          test: /\.(js|mjs|jsx)$/,
          enforce: 'pre',
          use: [
            {
              options: {
                formatter: require.resolve('react-dev-utils/eslintFormatter'),
                eslintPath: require.resolve('eslint'),

              },
              loader: require.resolve('eslint-loader'),
            },
          ],
          include: paths.appSrc,
        },

注意

  1. 找不到source-map可以在app.js里面console.log('app')一下

支持类静态方法

@babel/plugin-proposal-class-properties .babelrc

Without options:

{
  "plugins": ["@babel/plugin-proposal-class-properties"]
}

Copy With options:

{
  "plugins": [
    ["@babel/plugin-proposal-class-properties", { "loose": true }]
  ]
}

import支持as语法

export * as types from "@babel/types";
@babel/plugin-proposal-export-namespace-from 
cisen commented 4 years ago

使用apollo

使用apollo传送门做关于react连接graphql的项目

一、项目搭建

 import React from 'react';
import ReactDOM from 'react-dom';
import ApolloClient from 'apollo-boost';
import { ApolloProvider, ApolloConsumer } from 'react-apollo';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

const apolloClient = new ApolloClient({ uri: 'http://localhost:4000/' });

// ReactDOM.render(<App />, document.getElementById('root'));

const ClientRender = () => {
    let appComponent = (
      <ApolloProvider client={apolloClient}>
          <ApolloConsumer>
            {client => <App client={client} />}
          </ApolloConsumer>
      </ApolloProvider>
    )
    ReactDOM.render(appComponent, document.getElementById('root'));
  };

  export default ClientRender();

serviceWorker.unregister();

function App(props) { const { client } = props; console.log(props); useEffect(() => { const querySQL = gql query { seat(id: 2) { seatLen } } ;

client.query({ query: querySQL }).then(({ data }) => {
  console.log('allBook==>', data);
});

}, []) return (

); }

export default App;