предисловие
Create React App(далее CRA) — скаффолд для создания React-приложений, отличается от других скаффолдов тем, что инкапсулирует в себе конфигурацию некоторых сложных инструментов (таких как webpack), так что пользователям не нужно заботиться о конкретной конфигурации эти инструменты, тем самым снижая стоимость сложности использования инструмента.
использоватьcreate-react-app
Постройте проект, не будетwebpack
элементы конфигурации для экспортаwebpack
, необходимо использоватьreact-script eject
, но это односторонняя операция,eject
После этого его невозможно восстановить. Если вы просто измените какую-то простую конфигурацию,eject
не обязательно.
Но некоторые разработчики, знакомые с веб-пакетом, могут захотеть внести некоторые изменения в конфигурацию веб-пакета, что им делать сейчас?
На самом деле мы можем изменить конфигурацию webpack следующими способами:
- выброс проекта
- Заменить пакет реактивных скриптов
- Используйте реагирующее приложение, перепрограммированное
- пакет скриптов + комбинация переопределения
Если вы боретесь с тем, как обращаться с элементами конфигурации реакции, следующее может вывести вас из голубого неба. Далее мы представим эти методы по отдельности.Настройка - это болезненный процесс.Пожалуйста, попробуйте его внимательно.Если он вам полезен,поставьте лайк и перешлите! ! Посмотрите, как использовать плагиныофициальная документация,
выброс проекта
После того, как проект создан с использованием CRA, проектpackage.json
Он дает такую команду:
{
...
"scripts": {
"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Это основной пакет CRA. В него интегрирована конфигурация по умолчанию некоторых сценариев и инструментов. Конфигурация по умолчанию использования CRA для создания проекта заключается в использовании этого пакета, но CRA также предоставляет другой способ создания проекта CRA, который то есть с помощью пакета пользовательских скриптов.
# 默认方式
$ create-react-app foo
# 自定义 scripts 包方式
$ create-react-app foo --scripts-version 自定义包
自定义包
Может быть в следующих формах:
-
react-scripts
Номер версии пакета, например.0.8.2
, эту форму можно использовать для установки более ранних версийreact-scripts
Сумка. - Имя пакета, который был опубликован в репозитории npm, например.
your-scripts
, который содержит измененную конфигурацию веб-пакета. - Сжатый файл в формате tgz, например
/your/local/scripts.tgz
, обычно пакет пользовательских скриптов, не опубликованный в репозитории npm, который можно использовать сnpm pack
генерация команд.
Таким образом, по сравнению с предыдущимeject
Это более гибкий способ изменить конфигурацию веб-пакета, и он может делать то же самое, что и CRA, путем обновления пакета сценариев для обновления функций проекта.
Структура пакета пользовательских скриптов может относиться кreact-scripts
Структура пакета, просто измените соответствующий файл конфигурации веб-пакета и установите необходимый загрузчик веб-пакета или пакет плагинов.
Индивидуальная конфигурация с перемонтированным приложением react-app
Уведомление
Реакция-приложение-перемонтировано 1.x с созданием-реагирования-приложением 1.x
Реакция-приложение-перемонтировано 2.x с созданием-реакции-приложением 2.x
Обновление версии приводит к несовместимости.Кроме того, react-app-rewired 2.x должен поддерживаться сообществом.
react-app-rewired@^2.0.0+
версия должна соответствоватьcustomize-cra
использовать
В версии react-app-rewired 1.x помимо предоставления метода переопределения конфигурации также используются некоторыеhelpers
, такие как rewireLess, rewirePreact и т. д. Версия 2.x сохраняет только основные функции.
From README:
Version 2.0 removes the rewire helper functions
All helper functions:
- injectBabelPlugin
- compose
- getBabelLoader
- getLoader
- babelLoaderMatcher
- loaderNameMatches
have been removed with commit 0848602
За нас это делает другой инструмент,customize-cra, на этот раз мы будем использоватьreact-app-rewired
иcustomize-cra
Смешайте вместе.
Хотя есть два способа расширить конфигурацию веб-пакета, многие разработчики по-прежнему считают его слишком громоздким.eject
Что, если проекту не нужно создавать собственный пакет скриптов? Ответ - да,react-app-rewiredЭто инструмент с открытым исходным кодом, открытый сообществом реагирования, для изменения конфигурации CRA.
чистыйreact-app-rewired
способ настройки конфигурации см.Extended Configuration Optionsдокументация.
На этот раз мы используемcustomize-cra
Помощь в настройке, ссылкаUsing the pluginsдокументация.
custom-cra предоставляет несколько простых API (customize-cra/api.md), которые обычно удовлетворяют большинство потребностей разработчиков.
Исходный код (customize-cra/src/customizes/webpack.js) (например, текущая версияGitHub.com/AR AC Coffee/Подсказка…)
Устанавливается в созданный проект CRAreact-app-rewired
После этого можно создатьconfig-overrides.js
файл для расширения конфигурации веб-пакета. Конкретные операции заключаются в следующем:
конфигурация config-overrides.js
1. Чтобы изменить файл конфигурации веб-пакета, вам необходимо установить react-app-rewired custom-cra.
yarn add react-app-rewired customize-cra -D
2. Измените файл package.json.
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test --env=jsdom",
"eject": "react-scripts eject"
},
3. Создайте новый файл config-overrides.js в корневом каталоге проекта.
const { override } = require('customize-cra');
module.exports = {};
4. Добавьте конфигурацию, междоменные настройки, уменьшите поддержку, px to rem, загрузку по запросу ant-design, упакуйте и сжимайте js и css
// 安装less less-loader
yarn add less less-loader -D
// 安装compression-webpack-plugin 压缩js为gzip
yarn add compression-webpack-plugin -D
const { override, overrideDevServer, addLessLoader, addPostcssPlugins, fixBabelImports } = require('customize-cra');
const CompressionWebpackPlugin = require('compression-webpack-plugin');
// 打包配置
const addCustomize = () => config => {
if (process.env.NODE_ENV === 'production') {
// 关闭sourceMap
config.devtool = false;
// 配置打包后的文件位置
config.output.path = __dirname + '../dist/demo/';
config.output.publicPath = './demo';
// 添加js打包gzip配置
config.plugins.push(
new CompressionWebpackPlugin({
test: /\.js$|\.css$/,
threshold: 1024,
}),
)
}
return config;
}
// 跨域配置
const devServerConfig = () => config => {
return {
...config,
// 服务开启gzip
compress: true,
proxy: {
'/api': {
target: 'xxx',
changeOrigin: true,
pathRewrite: {
'^/api': '/api',
},
}
}
}
}
module.exports = {
webpack: override(
fixBabelImports('import', {
libraryName: 'antd-mobile',
style: 'css',
}),
addLessLoader(),
addPostcssPlugins([require('postcss-pxtorem')({ rootValue: 75, propList: ['*'], minPixelValue: 2, selectorBlackList: ['am-'] })]),
addCustomize(),
),
devServer: overrideDevServer(
devServerConfig()
)
}
5. и тд
Предположим, мы хотим использовать antd, см.Расширенная конфигурациядокументация.
npm i --save-dev babel-plugin-import
npm i --save antd
const { override, fixBabelImports, addLessLoader } = require('customize-cra');
module.exports = override(
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: true,
}),
addLessLoader({
javascriptEnabled: true,
modifyVars: { '@primary-color': '#1DA57A' },
localIdentName: '[local]--[hash:base64:5]' // 自定义 CSS Modules 的 localIdentName
}),
);
6, декораторы
в приложении "создать-реагировать"Can I Use DecoratorsВ документе сказано, что в настоящее время он не является спецификацией документа и не рекомендуется по умолчанию, если вы хотите его использовать, вам нужно вручную открыть его самостоятельно.
npm i --save-dev @babel/plugin-proposal-decorators
const { override, fixBabelImports, addLessLoader, addDecoratorsLegacy } = require('customize-cra');
module.exports = override(
addDecoratorsLegacy(),
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: true,
}),
addLessLoader({
javascriptEnabled: true,
modifyVars: { '@primary-color': '#1DA57A' },
localIdentName: '[local]--[hash:base64:5]' // 自定义 CSS Modules 的 localIdentName
}),
);
7. Добавьте псевдонимы
const { override, fixBabelImports, addLessLoader, addDecoratorsLegacy, addWebpackAlias } = require('customize-cra');
module.exports = override(
addDecoratorsLegacy(),
addWebpackAlias({
["ag-grid-react$"]: path.resolve(__dirname, "src/shared/agGridWrapper.js")
}),
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: true,
}),
addLessLoader({
javascriptEnabled: true,
modifyVars: { '@primary-color': '#1DA57A' },
localIdentName: '[local]--[hash:base64:5]' // 自定义 CSS Modules 的 localIdentName
}),
);
8. Добавьте react-hot-reloader и включите react-hot-reloader в корневом компоненте.
# https://www.npmjs.com/package/react-hot-loader
# https://github.com/cdharris/react-app-rewire-hot-loader
$ npm i react-hot-loader -D
$ npm i react-app-rewire-hot-loader @hot-loader/react-dom -D
Затем выполните следующие настройки в App.js.
import React, { Component } from 'react'
import { hot } from 'react-hot-loader/root'
class App extends Component {
render() {
return (
<>测试</>
)
}
}
const AppHot = process.env.NODE_ENV === 'development' ? hot(App) : App
export default AppHot
9. Закрыть исходную карту
-
Вариант 1. Измените сборку скриптов в пакете.
"build": "GENERATE_SOURCEMAP=false react-app-rewired build"
-
Вариант 2:
const rewiredMap = () => config => { config.devtool = config.mode === 'development' ? 'cheap-module-source-map' : false
return config }
10. Загрузка по требованию, оптимизация lodash
ant-design-mobile, ant-design загружаются по запросу
Есть несколько вариантов, которые можно попробовать:
方法一:
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: true
}),
fixBabelImports('babel-plugin-import', {
libraryName: 'antd-mobile',
libraryDirectory: 'es',
style: true
}),
方法二:
fixBabelImports('antd', {
libraryName: 'antd',
libraryDirectory: 'es',
style: true
}),
fixBabelImports('antd-mobile', {
libraryName: 'antd-mobile',
libraryDirectory: 'es',
style: true
}),
Оптимизируйте с помощью плагинов
lodash
В качестве наиболее часто используемого набора инструментов для разработки интерфейса, использование веб-пакета дляvendor
В практике разделения встречается, что всяlodash
файл разделен наvendor.js
Проблема. Это сделаетvendor.js
Файл становится очень большим.
в соответствии сbabel-plugin-lodash
Обратитесь к документации для ознакомления, используйтеlodash-webpack-plugin
может быть дополнительно сжатоlodash
.
Установитьlodash-webpack-plugin
полагаться:
yarn add lodash-webpack-plugin --dev
Добавьте файл конфигурации следующим образом:
const LodashWebpackPlugin = require('lodash-webpack-plugin')
addWebpackPlugin({
new LodashWebpackPlugin({
collections: true,
paths: true
}),
})
На самом деле этот шаг все же необходим.Сначала создайте свой файл .bable или измените его прямо в package.json.Следующий метод использует прежний
{
"presets": ["react-app"],
// 开发环境下配置项
"env": {
"development": {
"plugins": ["dynamic-import-node"]
}
},
"plugins": [
[
"module-resolver",
{
"alias": {
"src": ["./src/"]
}
}
],
[
"import",
{
"libraryName": "lodash",
"libraryDirectory": "",
"camel2DashComponentName": false
}
],
[
"@babel/plugin-transform-modules-commonjs",
{
"allowTopLevelThis": true
}
]
]
}
**Примечание: **Как правило, не используйтеlodash-webpack-plugin
Он может удовлетворить потребности разработки, но рекомендуется использовать его, когда файл особенно велик.
Используйте lodash-es
В качестве ключевой функции сверты, встряхивание дерева может использовать преимущества спецификации статического импорта ES6, чтобы уменьшить размер пакета и избежать ненужного ввода кода.Webpack2 также быстро представил эту функцию.
Чтобы использовать древовидную структуру, необходимо убедиться, что модули, на которые ссылаются, соответствуют спецификациям ES6. lodash-es — это версия с модульностью ES6, просто импортируйте ее напрямую.
import {isEmpty, isObject, cloneDeep} from 'lodash-es';
Видно, что после использования оптимизации lodash меняется от исходного70.7kbсокращено до20.2kbЭффект все равно виден.
Вы можете обратиться по следующей ссылке:
Вууху.Основное 51.net/article/113…
оооооооооооо эта лошадь plus.com/package/cluck…
Выше приведены некоторые простые конфигурации.
Общий файл конфигурации выглядит следующим образом:
const {
override,
fixBabelImports,
addLessLoader,
addWebpackAlias,
addBabelPlugins,
addWebpackPlugin,
useBabelRc,
disableChunk,
adjustWorkbox,
setWebpackPublicPath,
addBundleVisualizer,
disableEsLint,
addWebpackExternals
// addBundleVisualizer
} = require('customize-cra')
const path = require('path')
const paths = require('react-scripts/config/paths')
const rewireReactHotLoader = require('react-app-rewire-hot-loader')
const CompressionWebpackPlugin = require('compression-webpack-plugin')
// const rewireCompressionPlugin = require('react-app-rewire-compression-plugin')
const rewireUglifyjs = require('react-app-rewire-uglifyjs')
const FilterWarningsPlugin = require('webpack-filter-warnings-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const LodashWebpackPlugin = require('lodash-webpack-plugin')// 补充:对开发友好,打包完成桌面提醒
const WebpackBuildNotifierPlugin = require('webpack-build-notifier')
const webpackConfig = require('./webpack.config.js')
// const ProgressBarPlugin = require('progress-bar-webpack-plugin')
// const Dashboard = require('webpack-dashboard')
// const DashboardPlugin = require('webpack-dashboard/plugin')
// const dashboard = new Dashboard()
const theme = require('./theme')
// SKIP_PREFLIGHT_CHECK = true
/**
* 生产环境是否打包 Source Map 两种方法
*
*/
const rewiredMap = () => config => {
config.devtool = config.mode === 'development' ? 'cheap-module-source-map' : false
return config
}
process.env.PORT = 3006
process.env.GENERATE_SOURCEMAP !== 'false'
console.log(process.env.NODE_ENV)
// const addWebpackModules = () => config => {
// const loaders = config.module.rules.find(rule => Array.isArray(rule.oneOf)).oneOf
// loaders[loaders.length - 4] = Object.assign(
// loaders[loaders.length - 4],
// webpackConfig.module.rules[0]
// )
// return config
// }
// path
const resolveAlias = dir => path.join(__dirname, '.', dir)
// 热跟新
const hotLoader = () => (config, env) => {
config = rewireReactHotLoader(config, env)
return config
}
// build--->prod --->文件设置
const appBuildPathFile = () => config => {
if (config.mode === 'development') {
console.log('evn is development, skip build path change...')
} else if (config.mode === 'production') {
console.log('evn is production, change build path...')
// 关闭sourceMap
config.devtool = false
// // 配置打包后的文件位置修改path目录
paths.appBuild = path.join(path.dirname(paths.appBuild), 'dist')
config.output.path = path.join(path.dirname(config.output.path), 'dist')
// 添加js打包gzip配置
// config.plugins.push(
// new CompressionWebpackPlugin({
// test: /\.js$|\.css$/,
// threshold: 1024
// })
// )
// 更改生产模式输出的文件名
// config.output.filename = 'static/js/[name].js?_v=[chunkhash:8]'
// config.output.chunkFilename = 'static/js/[name].chunk.js?_v=[chunkhash:8]'
}
return config
}
//生产环境去除console.* functions
const dropConsole = () => {
return config => {
if (config.optimization.minimizer) {
config.optimization.minimizer.forEach(minimizer => {
if (minimizer.constructor.name === 'TerserPlugin') {
minimizer.options.terserOptions.compress.drop_console = true
}
})
}
return config
}
}
/**
*
* @description 解决打包的时候如下报错
* @url{https://github.com/ant-design/ant-design/issues/15696}
* https://blog.csdn.net/peade/article/details/84890399
chunk 3 [mini-css-extract-plugin]
Conflicting order between:
* css ./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-7-1!./node_modules/postcss-loader/src??postcss!./node_modules/less-loader/dist/cjs.js??ref--6-oneOf-7-3!./node_modules/antd/es/input/style/index.less
* css ./node_modules/css-loader/dist/cjs.js??ref--6-oneOf-7-1!./node_modules/postcss-loader/src??postcss!./node_modules/less-loader/dist/cjs.js??ref--6-oneOf-7-3!./node_modules/antd/es/message/style/index.less
*/
const delConflictingOrder = () => {
return config => {
for (let i = 0; i < config.plugins.length; i++) {
const p = config.plugins[i]
if (!!p.constructor && p.constructor.name === MiniCssExtractPlugin.name) {
const miniCssExtractOptions = { ...p.options, ignoreOrder: true }
config.plugins[i] = new MiniCssExtractPlugin(miniCssExtractOptions)
break
}
}
}
}
const addMiniCssExtractPlugin = () => {
return config => {
config.plugins.unshift(
new FilterWarningsPlugin({
// exclude: /any-warnings-matching-this-will-be-hidden/
// exclude: /mini-css-extract-plugin[^]*Conflicting order between:/
exclude: /\[mini-css-extract-plugin\][^]*Conflicting order between:/
})
)
}
}
const proxyApi = {
'/api': {
// target: '', // prod
changeOrigin: true,
secure: false,
xfwd: false,
pathRewrite: {
'^/api': '/'
}
},
'/store': {
// target: '', // staging
changeOrigin: true,
secure: false,
xfwd: false,
pathRewrite: {
'^/store': '/'
}
}
}
module.exports = {
webpack: override(
fixBabelImports('import', {
libraryName: 'antd',
libraryDirectory: 'es',
style: true
}),
addLessLoader({
// strictMath: true,
noIeCompat: true,
javascriptEnabled: true,
modifyVars: { ...theme }
// localIdentName: '[local]--[hash:base64:5]', // 自定义 CSS Modules 的 localIdentName
}),
setWebpackPublicPath('/hostsec'), // 修改 publicPath
addWebpackExternals({
React: 'React',
lodash: 'Lodash'
}),
// addWebpackModules(),
addWebpackAlias({
'@': resolveAlias('src'),
lib: resolveAlias('src/lib'),
components: resolveAlias('src/components'),
images: resolveAlias('src/assets/images'),
styled: resolveAlias('src/assets/styled'),
views: resolveAlias('src/views'),
store: resolveAlias('src/store'),
router: resolveAlias('src/router'),
locale: resolveAlias('src/locale'),
// 处理警告 React-Hot-Loader: react-🔥-dom patch is not detected. React 16.6+ features may not work.
'react-dom': '@hot-loader/react-dom'
// 解决antd 的icon图标打包体积大
// '@ant-design/icons': 'purched-antd-icons'
}),
disableEsLint(),
appBuildPathFile(),
disableChunk(),
dropConsole(),
// 关闭mapSource
rewiredMap(),
// 热跟新
hotLoader(),
// 配置babel解析器
addBabelPlugins(['@babel/plugin-proposal-decorators', { legacy: true }]),
//启用ES7的修改器语法(babel 7)
// ['@babel/plugin-proposal-decorators', {legacy: true}],
// ['@babel/plugin-proposal-class-properties', {loose: true}],
// 打包编译完成提醒
addWebpackPlugin(
new WebpackBuildNotifierPlugin({
title: '',
logo: path.resolve('./public/logo.svg'),
suppressSuccess: true
}),
new MiniCssExtractPlugin({
filename: 'static/css/[name].[contenthash].css',
chunkFilename: 'static/css/[id].[contenthash].css',
ignoreOrder: false
// moduleFilename: ({ name }) => `${name.replace('/js/', '/css/')}.css`
}),
new LodashWebpackPlugin({ collections: true, paths: true }), // 美化控制台
// new DashboardPlugin(dashboard.setData),
// 进度条
// new ProgressBarPlugin(),
delConflictingOrder(),
addMiniCssExtractPlugin()
),
rewireUglifyjs,
// rewireCompressionPlugin,
// 允许使用.babelrc文件进行Babel配置。
useBabelRc(),
// add webpack bundle visualizer if BUNDLE_VISUALIZE flag is enabled
process.env.BUNDLE_VISUALIZE == 1 && addBundleVisualizer(),
adjustWorkbox(wb =>
Object.assign(wb, {
skipWaiting: true,
exclude: (wb.exclude || []).concat('index.html')
})
)
// addDecoratorsLegacy() // 解析器,
),
// 配置devServer
// devServer: overrideDevServer(
// // dev server plugin
// watchAll(),
// ),
// 配置devServer
devServer: configFunction => (proxy, allowedHost) => {
proxy = process.env.NODE_ENV === 'development' ? proxyApi : null
// allowedHost: 添加额外的地址
const config = configFunction(proxy, allowedHost)
return config
}
}
㊗️ Примечание: Если вы хотите добавить конфигурацию, вы можете вставить ее самостоятельно. Конкретные поддерживаемые методы следующие:
Портал**api.md**
Эпилог: анализ кода конфигурации
На данный момент предполагается, что некоторые студенты не удовлетворены тем, почему приведенный выше код может решить проблему, поэтому я объясню это в соответствии с моим пониманием.
const path = require('path');
Эта строка кода основана наrequire.js
, это инструмент для js для импорта пакетов. С помощью этой строки кода вы можете получить путь до того, как сможете его обработать.
const paths = require('react-scripts/config/paths');
react-scripts
Есть команды, используемые проектом React для упаковки, а также файлы конфигурации.Если вы извлечете, вы обнаружите, что содержимое каталогов config и script такое же, как иreact-scripts
Одноименный каталог поразительно похож. Можно считать, что здесь eject выставляет конфигурацию. Эта строка кода предназначена для получения конфигурации пути проекта.
paths.appBuild = path.join(path.dirname(paths.appBuild), 'dist');
Эта строка кода предназначена для изменения каталога appBuild в конфигурации.При сборке проекта React он будет выполнять операции на основе настроенного здесь каталога (например, проверка размера упакованного кода, вычисление Gzip и т. д.). должны быть изменены, иначе упаковка будет Fail.
config.output.path = path.join(path.dirname(config.output.path), 'dist');
Эта строка кода является корнем нашей цели, изменить адрес упаковки проекта.
Суммировать
CRA — отличный инструмент для формирования шаблонов React, но если вас не устраивает стандартная конфигурация веб-пакета, вы можете расширить конфигурацию веб-пакета вашего проекта с помощью описанных выше методов.Эти методы имеют свои преимущества и недостатки, и их можно комбинировать с конкретным сцену, чтобы выбрать способ, который работает для вас.
Ну вот и конец этой статьи. Если эта статья была вам полезна, подписывайтесь, ставьте лайки и собирайте.
в то же время, приглашаем друзей присоединиться к группе WeChat, чтобы обсудить:
Мы общаемся по номеру
Ссылка на документацию:
- create-react-app Facebook.GitHub.IO/create-hot eat...
- customize-cra GitHub.com/AR AC Coffee/Подсказка…
- ant-design используется в приложении create-реагироватьAnta.design/docs/реагировать/…
Основные требования могут быть выполнены, в том числе: введение по запросу, присоединение Меньше - Добавьте прокси для локальной разработки и кросс-доменного официального сайта create-react-app:Facebook.GitHub.IO/create-hot eat...
- http-proxy-middleware GitHub.com/любовь к грудному вскармливанию/контракт…
- react-hot-loader GitHub.com/GAE Рон/Горячие…
- react-hot-loader without eject [react-app-rewire-hot-loader] GitHub.com/CD Харрис/Горячие…
- анализ и настройка конфигурации веб-пакета по умолчанию create-реагировать-приложение
- nuggets.capable/post/684490…