前言:
好久没用 create-react-app做项目了,这次为了个h5项目,就几个页面,决定自己搭建一个(ps:mmp 好久没用,搭建的时候遇到一堆问题)。
我之前都是使用 umi 。后台管理系统的项目 使用 antd-pro框架。实际上antd-pro 是基于umi搭建集成的框架。里面封装好了各种东西,开箱即用。
如果不想暴露 eject 可以参考 :
react create-react-app v5 从零搭建项目 不暴露 eject
我的环境如下:
create-react-app v5
"axios": "^1.5.0","http-proxy-middleware": "^2.0.6","react": "^18.2.0","react-dom": "^18.2.0","react-router": "^6.16.0","react-router-dom": "^6.16.0",
搭建过程:
一、创建项目:
安装Node 和 npm: Node >= 14.0.0 和 npm >= 5.6
npx install -g create-react-app
npx create-react-app my-app
npx 不是拼写错误 —— 它是 npm 5.2+ 附带的 package 运行工具。
react 官网文档
二、配置各种必备的东西
npm start 运行 看到下图就说明项目创建成功了!
运行 npm run eject 此命令一旦运行不可逆!!!
如果不想 用这种方式可以参考:
react create-react-app v5 从零搭建项目 不运行 eject
配置less:
1.安装 less和less-loader
npm install less less-loader --save-dev
2.找到 config/webpack.config.js 添加less规则代码如下:
const lessRegex = /\.less$/;
const lessModuleRegex = /\.module\.less$/;
3.搜索oneOf,在oneOf数组中添加以下代码:
//less 配置{test: lessRegex,exclude: lessModuleRegex,use: getStyleLoaders({importLoaders: 2,sourceMap: isEnvProduction? shouldUseSourceMap: isEnvDevelopment,},"less-loader"),sideEffects: true,},//less 模块化配置{test: lessModuleRegex,use: getStyleLoaders({importLoaders: 2,sourceMap: isEnvProduction? shouldUseSourceMap: isEnvDevelopment,modules: {getLocalIdent: getCSSModuleLocalIdent,},},"less-loader"),},
要放到 sass-loader下面,位置不对可能不生效
我一开始放到了这里(错误示范)就不生效。
4.重新 npm start(修改 webpack.config.js里的东西 都要重新运行,别忘记保存!!!)
然后 直接 import ‘./App.less’ 或者 模块化引入 import styles from “./index.module.less”(当然 App.less 也要改成 App.module.less)。
看到 和 App.css运行的效果一样则说明配置成功。
配置路由:
1.下载 react-router-dom
npm install react-router-dom
2.App.js 里 写上如下代码:
import React from "react";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import routes from './routes';
const App = () => {console.log(routes)return (<BrowserRouter><Routes>{routes.map((route) => (<Route key={route.path} path={route.path} element={route.component} />))}{/* <Route path="*" element={<Home />} /> */}</Routes></BrowserRouter>);
};export default App;
遇到 Uncaught TypeError: Cannot read properties of null (reading ‘useRef‘) 报错可以看:
react create-react-app 配置路由报错(Uncaught TypeError: Cannot read properties of null (reading ‘useRef‘))
3.index.js里写上:
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(<React.StrictMode><App /></React.StrictMode>
);// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
4.在src下新建一个 routes.js文件 写上:
// 导入你的页面组件
import Home from './pages';
const routes = [{ path: "/", component: <Home/>}
];export default routes;
运行看到 Home组件里的东西就说明成功了。之后可以在 scr/router.js里导入其他组件 写上 path和routers就行了。
注意:react-router-dom v6 和v5 api不太一样,比如 v5 把 Route 上是 component v6是element。具体写法 建议参考 你所用的版本 文档!
如果遇到了Uncaught TypeError: Cannot read properties of null (reading ‘useRef‘) 报错,可以看https://blog.csdn.net/weixin_44058725/article/details/133316898
配置axios:
1.安装 axios
cnpm install axios --save
2.src/utils 新建一个 request.js文件(没有utils就新建一个目录然后再建一个request.js)
3.request代码如下:
这个是最简单的配置了,你可以根据自己的需求配置 请求拦截里的东西。
import axios from 'axios'// axios的配置文件, 可以在这里去区分开发环境和生产环境等全局一些配置const devBaseUrl = 'http://api.k780.com/'const proBaseUrl = 'http://xxxxx.com/'// process.env返回的是一个包含用户的环境信息,它可以去区分是开发环境还是生产环境export const BASE_URL = process.env.NODE_ENV === 'development' ? devBaseUrl : proBaseUrlexport const TIMEOUT = 5000var request = axios.create({baseURL:BASE_URL,//基准地址timeout:TIMEOUT
})
//拦截请求
request.interceptors.request.use((config)=>{return config
})
//拦截响应
request.interceptors.response.use((response)=>{return response
},function (error){//对响应的错误做点什么return Promise.reject(error);
}
)export default request;
配置Proxy代理:
使用 http-proxy-middleware
1.安装http-proxy-middleware
npm install http-proxy-middleware --save
2.根目录新建一个setupProxy.js
代码大致如下:
然后 请求接口时以/api/xx就会自动走代理。
const { createProxyMiddleware } = require('http-proxy-middleware');module.exports = function(app) {app.use('/api',createProxyMiddleware({target: 'http://localhost:8000',changeOrigin: true,// pathRewrite: { // '^/api': '/', // }, }));};
配置 px2rem:
具体请看:react create-react-app v5配置 px2rem (暴露 eject方式)
配置别名 src可以用 @ :
1.在 config/webpack.config.js里搜索 alias 然后 加上
"@": paths.appSrc,
2.在 App.js里测试一下,引入 app的样式文件,我是 App.less。
import ‘@/App.less’;
3.重新运行 npm start 如果,样式确实生效了就说明,配置对了。
配置按需加载:
注意:antd-mobile无需配置手动按需加载
antd-mobile 按需加载
其实 antd 高版本也自带按需加载 可以不用配置(下面的代码只是个 演示,你如果有其他 ui库 或者 插件需要按需加载可以按照下面的步骤来):
antd 官方链接 按需加载
如果你有其他插件需要配置可以参考这个步骤来:
1.找到 config/webpack.config.js 然后 搜索 oneOf 在下面加一个配置:
其实和配置less差不多。
{ //配置按需加载 test: /\.less$/, use: [ 'style-loader', 'css-loader', 'less-loader', { loader: 'babel-loader', options: { plugins: [ [ 'import', { libraryName: 'antd', libraryDirectory: 'es', style: true, // 如果你使用的是 less,则设置为 true }, ], ], }, }, ], include: /node_modules/, },
我的 webpack.config.js完整的配置:
你可以参考对比:
'use strict';const fs = require('fs');
const path = require('path');
const webpack = require('webpack');
const resolve = require('resolve');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const InlineChunkHtmlPlugin = require('react-dev-utils/InlineChunkHtmlPlugin');
const TerserPlugin = require('terser-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const WorkboxWebpackPlugin = require('workbox-webpack-plugin');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const getCSSModuleLocalIdent = require('react-dev-utils/getCSSModuleLocalIdent');
const ESLintPlugin = require('eslint-webpack-plugin');
const paths = require('./paths');
const modules = require('./modules');
const getClientEnvironment = require('./env');
const ModuleNotFoundPlugin = require('react-dev-utils/ModuleNotFoundPlugin');
const ForkTsCheckerWebpackPlugin =process.env.TSC_COMPILE_ON_ERROR === 'true'? require('react-dev-utils/ForkTsCheckerWarningWebpackPlugin'): require('react-dev-utils/ForkTsCheckerWebpackPlugin');
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');const createEnvironmentHash = require('./webpack/persistentCache/createEnvironmentHash');//px2rem的配置
const px2rem = require("postcss-plugin-px2rem");
const px2remOpts = {rootValue: 37.5, //这个值定义了1rem应该等于多少像素。在这里,1rem等于37.5exclude: /(node_module)/, //这是一个正则表达式,用于指定哪些文件应该被排除在转换之外。在这里,所有在'node_module'目录下的文件都将被排除。// mediaQuery: false, //这个选项表示是否应该在媒体查询中转换px单位。在这里,它被设置为false,意味着媒体查询中的px单位将不会被转换// minPixelValue: 3, //这个选项表示应该转换的最小px值。在这里,只有px值大于或等于3的才会被转换
};// Source maps are resource heavy and can cause out of memory issue for large source files.
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';const reactRefreshRuntimeEntry = require.resolve('react-refresh/runtime');
const reactRefreshWebpackPluginRuntimeEntry = require.resolve('@pmmmwh/react-refresh-webpack-plugin'
);
const babelRuntimeEntry = require.resolve('babel-preset-react-app');
const babelRuntimeEntryHelpers = require.resolve('@babel/runtime/helpers/esm/assertThisInitialized',{ paths: [babelRuntimeEntry] }
);
const babelRuntimeRegenerator = require.resolve('@babel/runtime/regenerator', {paths: [babelRuntimeEntry],
});// Some apps do not need the benefits of saving a web request, so not inlining the chunk
// makes for a smoother build process.
const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false';const emitErrorsAsWarnings = process.env.ESLINT_NO_DEV_ERRORS === 'true';
const disableESLintPlugin = process.env.DISABLE_ESLINT_PLUGIN === 'true';const imageInlineSizeLimit = parseInt(process.env.IMAGE_INLINE_SIZE_LIMIT || '10000'
);// Check if TypeScript is setup
const useTypeScript = fs.existsSync(paths.appTsConfig);// Check if Tailwind config exists
const useTailwind = fs.existsSync(path.join(paths.appPath, 'tailwind.config.js')
);// Get the path to the uncompiled service worker (if it exists).
const swSrc = paths.swSrc;// style files regexes
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;
const lessRegex = /\.less$/;
const lessModuleRegex = /\.module\.less$/;const hasJsxRuntime = (() => {if (process.env.DISABLE_NEW_JSX_TRANSFORM === 'true') {return false;}try {require.resolve('react/jsx-runtime');return true;} catch (e) {return false;}
})();// This is the production and development configuration.
// It is focused on developer experience, fast rebuilds, and a minimal bundle.
module.exports = function (webpackEnv) {const isEnvDevelopment = webpackEnv === 'development';const isEnvProduction = webpackEnv === 'production';// Variable used for enabling profiling in Production// passed into alias object. Uses a flag if passed into the build commandconst isEnvProductionProfile =isEnvProduction && process.argv.includes('--profile');// We will provide `paths.publicUrlOrPath` to our app// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.// Get environment variables to inject into our app.const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));const shouldUseReactRefresh = env.raw.FAST_REFRESH;// common function to get style loadersconst getStyleLoaders = (cssOptions, preProcessor) => {const loaders = [isEnvDevelopment && require.resolve('style-loader'),isEnvProduction && {loader: MiniCssExtractPlugin.loader,// css is located in `static/css`, use '../../' to locate index.html folder// in production `paths.publicUrlOrPath` can be a relative pathoptions: paths.publicUrlOrPath.startsWith('.')? { publicPath: '../../' }: {},},{loader: require.resolve('css-loader'),options: cssOptions,},{// Options for PostCSS as we reference these options twice// Adds vendor prefixing based on your specified browser support in// package.jsonloader: require.resolve('postcss-loader'),options: {postcssOptions: {// Necessary for external CSS imports to work// https://github.com/facebook/create-react-app/issues/2677ident: 'postcss',config: false,plugins: !useTailwind? ['postcss-flexbugs-fixes',['postcss-preset-env',{autoprefixer: {flexbox: 'no-2009',},stage: 3,},],[px2rem(px2remOpts)],// Adds PostCSS Normalize as the reset css with default options,// so that it honors browserslist config in package.json// which in turn let's users customize the target behavior as per their needs.'postcss-normalize',]: ['tailwindcss','postcss-flexbugs-fixes',['postcss-preset-env',{autoprefixer: {flexbox: 'no-2009',},stage: 3,},],],},sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,}} ].filter(Boolean);if (preProcessor) {loaders.push({loader: require.resolve('resolve-url-loader'),options: {sourceMap: isEnvProduction ? shouldUseSourceMap : isEnvDevelopment,root: paths.appSrc,},},{loader: require.resolve(preProcessor),options: {sourceMap: true,},});}return loaders;};return {target: ['browserslist'],// Webpack noise constrained to errors and warningsstats: 'errors-warnings',mode: isEnvProduction ? 'production' : isEnvDevelopment && 'development',// Stop compilation early in productionbail: isEnvProduction,devtool: isEnvProduction? shouldUseSourceMap? 'source-map': false: isEnvDevelopment && 'cheap-module-source-map',// These are the "entry points" to our application.// This means they will be the "root" imports that are included in JS bundle.entry: paths.appIndexJs,output: {// The build folder.path: paths.appBuild,// Add /* filename */ comments to generated require()s in the output.pathinfo: isEnvDevelopment,// There will be one main bundle, and one file per asynchronous chunk.// In development, it does not produce real files.filename: isEnvProduction? 'static/js/[name].[contenthash:8].js': isEnvDevelopment && 'static/js/bundle.js',// There are also additional JS chunk files if you use code splitting.chunkFilename: isEnvProduction? 'static/js/[name].[contenthash:8].chunk.js': isEnvDevelopment && 'static/js/[name].chunk.js',assetModuleFilename: 'static/media/[name].[hash][ext]',// webpack uses `publicPath` to determine where the app is being served from.// It requires a trailing slash, or the file assets will get an incorrect path.// We inferred the "public path" (such as / or /my-project) from homepage.publicPath: paths.publicUrlOrPath,// Point sourcemap entries to original disk location (format as URL on Windows)devtoolModuleFilenameTemplate: isEnvProduction? info =>path.relative(paths.appSrc, info.absoluteResourcePath).replace(/\\/g, '/'): isEnvDevelopment &&(info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')),},cache: {type: 'filesystem',version: createEnvironmentHash(env.raw),cacheDirectory: paths.appWebpackCache,store: 'pack',buildDependencies: {defaultWebpack: ['webpack/lib/'],config: [__filename],tsconfig: [paths.appTsConfig, paths.appJsConfig].filter(f =>fs.existsSync(f)),},},infrastructureLogging: {level: 'none',},optimization: {minimize: isEnvProduction,minimizer: [// This is only used in production modenew TerserPlugin({terserOptions: {parse: {// We want terser to parse ecma 8 code. However, we don't want it// to apply any minification steps that turns valid ecma 5 code// into invalid ecma 5 code. This is why the 'compress' and 'output'// sections only apply transformations that are ecma 5 safe// https://github.com/facebook/create-react-app/pull/4234ecma: 8,},compress: {ecma: 5,warnings: false,// Disabled because of an issue with Uglify breaking seemingly valid code:// https://github.com/facebook/create-react-app/issues/2376// Pending further investigation:// https://github.com/mishoo/UglifyJS2/issues/2011comparisons: false,// Disabled because of an issue with Terser breaking valid code:// https://github.com/facebook/create-react-app/issues/5250// Pending further investigation:// https://github.com/terser-js/terser/issues/120inline: 2,},mangle: {safari10: true,},// Added for profiling in devtoolskeep_classnames: isEnvProductionProfile,keep_fnames: isEnvProductionProfile,output: {ecma: 5,comments: false,// Turned on because emoji and regex is not minified properly using default// https://github.com/facebook/create-react-app/issues/2488ascii_only: true,},},}),// This is only used in production modenew CssMinimizerPlugin(),],},resolve: {// This allows you to set a fallback for where webpack should look for modules.// We placed these paths second because we want `node_modules` to "win"// if there are any conflicts. This matches Node resolution mechanism.// https://github.com/facebook/create-react-app/issues/253modules: ['node_modules', paths.appNodeModules].concat(modules.additionalModulePaths || []),// These are the reasonable defaults supported by the Node ecosystem.// We also include JSX as a common component filename extension to support// some tools, although we do not recommend using it, see:// https://github.com/facebook/create-react-app/issues/290// `web` extension prefixes have been added for better support// for React Native Web.extensions: paths.moduleFileExtensions.map(ext => `.${ext}`).filter(ext => useTypeScript || !ext.includes('ts')),alias: {// Support React Native Web// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/'react-native': 'react-native-web',// Allows for better profiling with ReactDevTools...(isEnvProductionProfile && {'react-dom$': 'react-dom/profiling','scheduler/tracing': 'scheduler/tracing-profiling',}),"@": paths.appSrc,...(modules.webpackAliases || {}),},plugins: [// Prevents users from importing files from outside of src/ (or node_modules/).// This often causes confusion because we only process files within src/ with babel.// To fix this, we prevent you from importing files out of src/ -- if you'd like to,// please link the files into your node_modules/ and let module-resolution kick in.// Make sure your source files are compiled, as they will not be processed in any way.new ModuleScopePlugin(paths.appSrc, [paths.appPackageJson,reactRefreshRuntimeEntry,reactRefreshWebpackPluginRuntimeEntry,babelRuntimeEntry,babelRuntimeEntryHelpers,babelRuntimeRegenerator,]),],},module: {strictExportPresence: true,rules: [// Handle node_modules packages that contain sourcemapsshouldUseSourceMap && {enforce: 'pre',exclude: /@babel(?:\/|\\{1,2})runtime/,test: /\.(js|mjs|jsx|ts|tsx|css)$/,loader: require.resolve('source-map-loader'),},{// "oneOf" will traverse all following loaders until one will// match the requirements. When no loader matches it will fall// back to the "file" loader at the end of the loader list.oneOf: [// TODO: Merge this config once `image/avif` is in the mime-db// https://github.com/jshttp/mime-db{test: [/\.avif$/],type: 'asset',mimetype: 'image/avif',parser: {dataUrlCondition: {maxSize: imageInlineSizeLimit,},},},// "url" loader works like "file" loader except that it embeds assets// smaller than specified limit in bytes as data URLs to avoid requests.// A missing `test` is equivalent to a match.{test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],type: 'asset',parser: {dataUrlCondition: {maxSize: imageInlineSizeLimit,},},},{test: /\.svg$/,use: [{loader: require.resolve('@svgr/webpack'),options: {prettier: false,svgo: false,svgoConfig: {plugins: [{ removeViewBox: false }],},titleProp: true,ref: true,},},{loader: require.resolve('file-loader'),options: {name: 'static/media/[name].[hash].[ext]',},},],issuer: {and: [/\.(ts|tsx|js|jsx|md|mdx)$/],},},// Process application JS with Babel.// The preset includes JSX, Flow, TypeScript, and some ESnext features.{test: /\.(js|mjs|jsx|ts|tsx)$/,include: paths.appSrc,loader: require.resolve('babel-loader'),options: {customize: require.resolve('babel-preset-react-app/webpack-overrides'),presets: [[require.resolve('babel-preset-react-app'),{runtime: hasJsxRuntime ? 'automatic' : 'classic',},],],plugins: [isEnvDevelopment &&shouldUseReactRefresh &&require.resolve('react-refresh/babel'),].filter(Boolean),// This is a feature of `babel-loader` for webpack (not Babel itself).// It enables caching results in ./node_modules/.cache/babel-loader/// directory for faster rebuilds.cacheDirectory: true,// See #6846 for context on why cacheCompression is disabledcacheCompression: false,compact: isEnvProduction,},},// Process any JS outside of the app with Babel.// Unlike the application JS, we only compile the standard ES features.{test: /\.(js|mjs)$/,exclude: /@babel(?:\/|\\{1,2})runtime/,loader: require.resolve('babel-loader'),options: {babelrc: false,configFile: false,compact: false,presets: [[require.resolve('babel-preset-react-app/dependencies'),{ helpers: true },],],cacheDirectory: true,// See #6846 for context on why cacheCompression is disabledcacheCompression: false,// Babel sourcemaps are needed for debugging into node_modules// code. Without the options below, debuggers like VSCode// show incorrect code and set breakpoints on the wrong lines.sourceMaps: shouldUseSourceMap,inputSourceMap: shouldUseSourceMap,},},// "postcss" loader applies autoprefixer to our CSS.// "css" loader resolves paths in CSS and adds assets as dependencies.// "style" loader turns CSS into JS modules that inject <style> tags.// In production, we use MiniCSSExtractPlugin to extract that CSS// to a file, but in development "style" loader enables hot editing// of CSS.// By default we support CSS Modules with the extension .module.css{test: cssRegex,exclude: cssModuleRegex,use: getStyleLoaders({importLoaders: 1,sourceMap: isEnvProduction? shouldUseSourceMap: isEnvDevelopment,modules: {mode: 'icss',},}),// Don't consider CSS imports dead code even if the// containing package claims to have no side effects.// Remove this when webpack adds a warning or an error for this.// See https://github.com/webpack/webpack/issues/6571sideEffects: true,},// Adds support for CSS Modules (https://github.com/css-modules/css-modules)// using the extension .module.css{test: cssModuleRegex,use: getStyleLoaders({importLoaders: 1,sourceMap: isEnvProduction? shouldUseSourceMap: isEnvDevelopment,modules: {mode: 'local',getLocalIdent: getCSSModuleLocalIdent,},}),},// Opt-in support for SASS (using .scss or .sass extensions).// By default we support SASS Modules with the// extensions .module.scss or .module.sass{test: sassRegex,exclude: sassModuleRegex,use: getStyleLoaders({importLoaders: 3,sourceMap: isEnvProduction? shouldUseSourceMap: isEnvDevelopment,modules: {mode: 'icss',},},'sass-loader'),// Don't consider CSS imports dead code even if the// containing package claims to have no side effects.// Remove this when webpack adds a warning or an error for this.// See https://github.com/webpack/webpack/issues/6571sideEffects: true,},// Adds support for CSS Modules, but using SASS// using the extension .module.scss or .module.sass{test: sassModuleRegex,use: getStyleLoaders({importLoaders: 3,sourceMap: isEnvProduction? shouldUseSourceMap: isEnvDevelopment,modules: {mode: 'local',getLocalIdent: getCSSModuleLocalIdent,},},'sass-loader'),},//less 配置{test: lessRegex,exclude: lessModuleRegex,use: getStyleLoaders({importLoaders: 2,sourceMap: isEnvProduction? shouldUseSourceMap: isEnvDevelopment,},"less-loader"),sideEffects: true,},//less 模块化配置{test: lessModuleRegex,use: getStyleLoaders({importLoaders: 2,sourceMap: isEnvProduction? shouldUseSourceMap: isEnvDevelopment,modules: {getLocalIdent: getCSSModuleLocalIdent,},},"less-loader"),},// { //配置按需加载 // test: /\.less$/, // use: [ // 'style-loader', // 'css-loader', // 'less-loader', // { // loader: 'babel-loader', // options: { // plugins: [ // [ // 'import', // { // libraryName: 'antd', // libraryDirectory: 'es', // style: true, // 如果你使用的是 less,则设置为 true // }, // ], // ], // }, // }, // ], // include: /node_modules/, // },// "file" loader makes sure those assets get served by WebpackDevServer.// When you `import` an asset, you get its (virtual) filename.// In production, they would get copied to the `build` folder.// This loader doesn't use a "test" so it will catch all modules// that fall through the other loaders.{// Exclude `js` files to keep "css" loader working as it injects// its runtime that would otherwise be processed through "file" loader.// Also exclude `html` and `json` extensions so they get processed// by webpacks internal loaders.exclude: [/^$/, /\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/],type: 'asset/resource',},// ** STOP ** Are you adding a new loader?// Make sure to add the new loader(s) before the "file" loader.],},].filter(Boolean),},plugins: [// Generates an `index.html` file with the <script> injected.new HtmlWebpackPlugin(Object.assign({},{inject: true,template: paths.appHtml,},isEnvProduction? {minify: {removeComments: true,collapseWhitespace: true,removeRedundantAttributes: true,useShortDoctype: true,removeEmptyAttributes: true,removeStyleLinkTypeAttributes: true,keepClosingSlash: true,minifyJS: true,minifyCSS: true,minifyURLs: true,},}: undefined)),// Inlines the webpack runtime script. This script is too small to warrant// a network request.// https://github.com/facebook/create-react-app/issues/5358isEnvProduction &&shouldInlineRuntimeChunk &&new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/]),// Makes some environment variables available in index.html.// The public URL is available as %PUBLIC_URL% in index.html, e.g.:// <link rel="icon" href="%PUBLIC_URL%/favicon.ico">// It will be an empty string unless you specify "homepage"// in `package.json`, in which case it will be the pathname of that URL.new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),// This gives some necessary context to module not found errors, such as// the requesting resource.new ModuleNotFoundPlugin(paths.appPath),// Makes some environment variables available to the JS code, for example:// if (process.env.NODE_ENV === 'production') { ... }. See `./env.js`.// It is absolutely essential that NODE_ENV is set to production// during a production build.// Otherwise React will be compiled in the very slow development mode.new webpack.DefinePlugin(env.stringified),// Experimental hot reloading for React .// https://github.com/facebook/react/tree/main/packages/react-refreshisEnvDevelopment &&shouldUseReactRefresh &&new ReactRefreshWebpackPlugin({overlay: false,}),// Watcher doesn't work well if you mistype casing in a path so we use// a plugin that prints an error when you attempt to do this.// See https://github.com/facebook/create-react-app/issues/240isEnvDevelopment && new CaseSensitivePathsPlugin(),isEnvProduction &&new MiniCssExtractPlugin({// Options similar to the same options in webpackOptions.output// both options are optionalfilename: 'static/css/[name].[contenthash:8].css',chunkFilename: 'static/css/[name].[contenthash:8].chunk.css',}),// Generate an asset manifest file with the following content:// - "files" key: Mapping of all asset filenames to their corresponding// output file so that tools can pick it up without having to parse// `index.html`// - "entrypoints" key: Array of files which are included in `index.html`,// can be used to reconstruct the HTML if necessarynew WebpackManifestPlugin({fileName: 'asset-manifest.json',publicPath: paths.publicUrlOrPath,generate: (seed, files, entrypoints) => {const manifestFiles = files.reduce((manifest, file) => {manifest[file.name] = file.path;return manifest;}, seed);const entrypointFiles = entrypoints.main.filter(fileName => !fileName.endsWith('.map'));return {files: manifestFiles,entrypoints: entrypointFiles,};},}),// Moment.js is an extremely popular library that bundles large locale files// by default due to how webpack interprets its code. This is a practical// solution that requires the user to opt into importing specific locales.// https://github.com/jmblog/how-to-optimize-momentjs-with-webpack// You can remove this if you don't use Moment.js:new webpack.IgnorePlugin({resourceRegExp: /^\.\/locale$/,contextRegExp: /moment$/,}),// Generate a service worker script that will precache, and keep up to date,// the HTML & assets that are part of the webpack build.isEnvProduction &&fs.existsSync(swSrc) &&new WorkboxWebpackPlugin.InjectManifest({swSrc,dontCacheBustURLsMatching: /\.[0-9a-f]{8}\./,exclude: [/\.map$/, /asset-manifest\.json$/, /LICENSE/],// Bump up the default maximum size (2mb) that's precached,// to make lazy-loading failure scenarios less likely.// See https://github.com/cra-template/pwa/issues/13#issuecomment-722667270maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,}),// TypeScript type checkinguseTypeScript &&new ForkTsCheckerWebpackPlugin({async: isEnvDevelopment,typescript: {typescriptPath: resolve.sync('typescript', {basedir: paths.appNodeModules,}),configOverwrite: {compilerOptions: {sourceMap: isEnvProduction? shouldUseSourceMap: isEnvDevelopment,skipLibCheck: true,inlineSourceMap: false,declarationMap: false,noEmit: true,incremental: true,tsBuildInfoFile: paths.appTsBuildInfoFile,},},context: paths.appPath,diagnosticOptions: {syntactic: true,},mode: 'write-references',// profile: true,},issue: {// This one is specifically to match during CI tests,// as micromatch doesn't match// '../cra-template-typescript/template/src/App.tsx'// otherwise.include: [{ file: '../**/src/**/*.{ts,tsx}' },{ file: '**/src/**/*.{ts,tsx}' },],exclude: [{ file: '**/src/**/__tests__/**' },{ file: '**/src/**/?(*.){spec|test}.*' },{ file: '**/src/setupProxy.*' },{ file: '**/src/setupTests.*' },],},logger: {infrastructure: 'silent',},}),!disableESLintPlugin &&new ESLintPlugin({// Plugin optionsextensions: ['js', 'mjs', 'jsx', 'ts', 'tsx'],formatter: require.resolve('react-dev-utils/eslintFormatter'),eslintPath: require.resolve('eslint'),failOnError: !(isEnvDevelopment && emitErrorsAsWarnings),context: paths.appSrc,cache: true,cacheLocation: path.resolve(paths.appNodeModules,'.cache/.eslintcache'),// ESLint class optionscwd: paths.appPath,resolvePluginsRelativeTo: __dirname,baseConfig: {extends: [require.resolve('eslint-config-react-app/base')],rules: {...(!hasJsxRuntime && {'react/react-in-jsx-scope': 'error',}),},},}),].filter(Boolean),// Turn off performance processing because we utilize// our own hints via the FileSizeReporterperformance: false,};
};
总结:
其实,我觉得暴露 eject配置起来还挺方便的。目前来看不暴露的话,会遇到不少问题。主要是第三方插件,没适配v5。
如果不想暴露 eject 可以参考 :
react create-react-app v5 从零搭建项目 不暴露 eject