记一次多页面应用实践

·  阅读 1028

eject暴露webpack配置信息

改造CRA项目,由react-app-rewired改为原生webpack构建

package.json(原)

"scripts": {
  "start": "set PORT=3000 && react-app-rewired start",
  "build": "react-app-rewired build",
  "test": "node scripts/test.js --env=jsdom",
  "lint": "eslint --ext .jsx --ext .js src --fix"
}复制代码
eject(yarn eject)

在eject之前,需要在package.json中新增eject命令,如下:

"scripts": {
  "start": "set PORT=3000 && react-app-rewired start",
  "build": "react-app-rewired build",
  "test": "node scripts/test.js --env=jsdom",
  "lint": "eslint --ext .jsx --ext .js src --fix",
  "eject": "react-scripts eject"// 新增eject
}复制代码

暴露出项目的webpack配置(该过程不可逆,请谨慎处理)


代码结构(原)

.
├─ .eslintignore
├─ .eslintrc
├─ .gitignore
├─ .project
├─ README.md
├─ build
│    ├─ asset-manifest.json
│    ├─ favicon.ico
│    ├─ index.html
│    ├─ manifest.json
│    ├─ service-worker.js
│    └─ static
│           ├─ css
│           ├─ js
│           └─ media
├─ config-overrides.js
├─ package-lock.json
├─ package.json
├─ public
│    ├─ favicon.ico
│    ├─ index.html
│    └─ manifest.json
├─ src
│    ├─ assets
│    │    ├─ fonts
│    │    ├─ images
│    │    └─ styles
│    ├─ config
│    │    └─ index.js
│    ├─ containers
│    │    ├─ AccountCenter
│    │    ├─ AddAccount
│    │    ├─ CampaignDetail
│    │    ├─ CampaignPlaza
│    │    ├─ CaseDetail
│    │    ├─ DefaultPage
│    │    ├─ FinancialCenter
│    │    ├─ ForgetLoginPassword
│    │    ├─ ForgetTriggerEmailSuccess
│    │    ├─ HelpCenter
│    │    ├─ HelpCenterFromLand
│    │    ├─ LatestNews
│    │    ├─ MyCase
│    │    ├─ PaymentDetails
│    │    ├─ PaymentInfo
│    │    ├─ RegSuccess
│    │    ├─ RegisterStep1
│    │    ├─ RegisterStep2
│    │    ├─ RegisterStep3
│    │    ├─ ResetLoginPassword
│    │    ├─ ResetSuccess
│    │    ├─ ResetWithdrawPassword
│    │    ├─ Simplest
│    │    ├─ UpdateUserInfo
│    │    ├─ WithdrawDetails
│    │    └─ Withdrawals
│    ├─ index.js
│    ├─ layout
│    │    ├─ HomeFooter
│    │    ├─ HomeHeader
│    │    ├─ LandFooter
│    │    ├─ PureHeader
│    │    └─ TopHeader
│    ├─ locales
│    │    ├─ en_US.js
│    │    └─ zh_CN.js
│    ├─ registerServiceWorker.js
│    ├─ route
│    │    └─ index.js
│    ├─ sagas
│    │    └─ index.js
│    ├─ store
│    │    └─ index.js
│    ├─ utils
│    │    ├─ RSA.js
│    │    ├─ async-component.js
│    │    ├─ index.js
│    │    ├─ request.js
│    │    ├─ request1.js
│    │    └─ upload.js
│    └─ views
│           ├─ Home
│           ├─ Land
│           ├─ Login
│           └─ Register
└─ yarn.lock复制代码

代码结构(新)

.
├─ .eslintignore
├─ .eslintrc
├─ .gitignore
├─ .project
├─ README.md
├─ build
│    ├─ asset-manifest.json
│    ├─ favicon.ico
│    ├─ index.html
│    ├─ manifest.json
│    ├─ service-worker.js
│    └─ static
│           ├─ css
│           ├─ js
│           └─ media
├─ config
│    ├─ env.js
│    ├─ jest
│    │    ├─ cssTransform.js
│    │    └─ fileTransform.js
│    ├─ paths.js// 路径信息
│    ├─ polyfills.js
│    ├─ webpack.config.dev.js// 开发环境配置信息
│    ├─ webpack.config.prod.js// 生产环境配合信息
│    └─ webpackDevServer.config.js
├─ config-overrides.js
├─ package-lock.json
├─ package.json
├─ public
│    ├─ favicon.ico
│    ├─ index.html
│    └─ manifest.json
├─ scripts
│    ├─ build.js
│    ├─ start.js
│    └─ test.js
├─ src
│    ├─ assets
│    │    ├─ fonts
│    │    ├─ images
│    │    └─ styles
│    ├─ config
│    │    └─ index.js
│    ├─ containers
│    │    ├─ AccountCenter
│    │    ├─ AddAccount
│    │    ├─ CampaignDetail
│    │    ├─ CampaignPlaza
│    │    ├─ CaseDetail
│    │    ├─ DefaultPage
│    │    ├─ FinancialCenter
│    │    ├─ ForgetLoginPassword
│    │    ├─ ForgetTriggerEmailSuccess
│    │    ├─ HelpCenter
│    │    ├─ HelpCenterFromLand
│    │    ├─ LatestNews
│    │    ├─ MyCase
│    │    ├─ PaymentDetails
│    │    ├─ PaymentInfo
│    │    ├─ RegSuccess
│    │    ├─ RegisterStep1
│    │    ├─ RegisterStep2
│    │    ├─ RegisterStep3
│    │    ├─ ResetLoginPassword
│    │    ├─ ResetSuccess
│    │    ├─ ResetWithdrawPassword
│    │    ├─ Simplest
│    │    ├─ UpdateUserInfo
│    │    ├─ WithdrawDetails
│    │    └─ Withdrawals
│    ├─ index.js
│    ├─ layout
│    │    ├─ HomeFooter
│    │    ├─ HomeHeader
│    │    ├─ LandFooter
│    │    ├─ PureHeader
│    │    └─ TopHeader
│    ├─ locales
│    │    ├─ en_US.js
│    │    └─ zh_CN.js
│    ├─ registerServiceWorker.js
│    ├─ route
│    │    └─ index.js
│    ├─ sagas
│    │    └─ index.js
│    ├─ store
│    │    └─ index.js
│    ├─ utils
│    │    ├─ RSA.js
│    │    ├─ async-component.js
│    │    ├─ index.js
│    │    ├─ request.js
│    │    ├─ request1.js
│    │    └─ upload.js
│    └─ views
│           ├─ Home
│           ├─ Land
│           ├─ Login
│           └─ Register
├─ yarn
├─ yarn-error.log
└─ yarn.lock复制代码

可以发现,eject之后,新的代码结构较原代码结构主要是新增了config目录和scripts目录,其中config目录为webpack配置信息存放目录,scripts目录为脚本文件存放目录。

动态切换组件(Vue->React)

ESearch前端架构(Vue)


以上为一个Vue前端项目的基本架构,基于该项目思路,特将之前做过的一个单页面应用改造为一个多页面应用,其前端架构如下:

网红前端架构(React)


可以发现,Vue项目可以通过Vue特性v-bind:is,实现菜单-组件动态切换(类似于路由的作用)

通过Vue特性v-bind:is,实现菜单-组件动态切换(类似于路由的作用)
components: {
    pageA: () => import("xxx/pageA"),
    pageB: () => import("xxx/pageB"),
}
<component v-bind:is="pageA"/>
<component v-bind:is="pageB"/>复制代码

类似地,React项目可以通过以下方法实现菜单-组件动态切换(类似于路由的作用)

import PageA from "@/containers/PageA";
import PageB from "@/containers/PageB";
import PageC from "@/containers/PageC";

const ComponentDict = {
    'PageA': PageA,
    'PageB': PageB,
    'PageC': PageC
};

constructor() {
    super();
    this.state = {
        currentComponentName: "PageA"
    }
}

onClickMenuItem = ({key}) => {
    this.setState({
        currentComponentName: key
    });
};

// 类似于查字典的方式,实现动态切换组件展示
const {currentComponentName} = this.state;
// currentComponentName为'PageA',则展示组件PageA
// currentComponentName为'PageB',则展示组件PageB
const CurrentComponent = ComponentDict[currentComponentName];// 动态切换组件展示

<Layout>
    <Header>
        <Menu onClick={this.onClickMenuItem}>
	    <Menu.Item key="PageA">PageA</Menu.Item>
	    <Menu.Item key="PageB">PageB</Menu.Item>
	    <Menu.Item key="PageC">PageC</Menu.Item>
        </Menu>
    </Header>
    <Content>
	<CurrentComponent/>
    </Content>
</Layout>复制代码

webpack配置修改

entry配置(定位:module.exports->entry,4个入口)

webpack.config.dev.js

// 单入口示例
/*
* entry: [
		require.resolve('./polyfills'),
		require.resolve('react-dev-utils/webpackHotDevClient'),
		paths.appSrc + '/index.js',
	]
*
* */
entry: {
	// We ship a few polyfills by default:
	// require.resolve('./polyfills'),
	// Include an alternative client for WebpackDevServer. A client's job is to
	// connect to WebpackDevServer by a socket and get notified about changes.
	// When you save a file, the client will either apply hot updates (in case
	// of CSS changes), or refresh the page (in case of JS changes). When you
	// make a syntax error, this client will display a syntax error overlay.
	// Note: instead of the default WebpackDevServer client, we use a custom one
	// to bring better experience for Create React App users. You can replace
	// the line below with these two lines if you prefer the stock client:
	// require.resolve('webpack-dev-server/client') + '?/',
	// require.resolve('webpack/hot/dev-server'),
	// require.resolve('react-dev-utils/webpackHotDevClient'),
	// Finally, this is your app's code:
	// paths.appIndexJs,
	// We include the app code last so that if there is a runtime error during
	// initialization, it doesn't blow up the WebpackDevServer client, and
	// changing JS code would still trigger a refresh.
	// created by lyb 2019/08/03
	// 多入口
	index: [
		require.resolve('./polyfills'),
		require.resolve('react-dev-utils/webpackHotDevClient'),
		paths.appSrc + '/index.js',
	],
	login: [
		require.resolve('./polyfills'),
		require.resolve('react-dev-utils/webpackHotDevClient'),
		paths.appSrc + '/login.js',
	],
	register: [
		require.resolve('./polyfills'),
		require.resolve('react-dev-utils/webpackHotDevClient'),
		paths.appSrc + '/register.js',
	],
	main: [
		require.resolve('./polyfills'),
		require.resolve('react-dev-utils/webpackHotDevClient'),
		paths.appSrc + '/main.js',
	]
},复制代码

webpack.config.prod.js

entry: {
	// We ship a few polyfills by default:
	// require.resolve('./polyfills'),
	// Include an alternative client for WebpackDevServer. A client's job is to
	// connect to WebpackDevServer by a socket and get notified about changes.
	// When you save a file, the client will either apply hot updates (in case
	// of CSS changes), or refresh the page (in case of JS changes). When you
	// make a syntax error, this client will display a syntax error overlay.
	// Note: instead of the default WebpackDevServer client, we use a custom one
	// to bring better experience for Create React App users. You can replace
	// the line below with these two lines if you prefer the stock client:
	// require.resolve('webpack-dev-server/client') + '?/',
	// require.resolve('webpack/hot/dev-server'),
	// require.resolve('react-dev-utils/webpackHotDevClient'),
	// Finally, this is your app's code:
	// paths.appIndexJs,
	// We include the app code last so that if there is a runtime error during
	// initialization, it doesn't blow up the WebpackDevServer client, and
	// changing JS code would still trigger a refresh.
	index: [
		require.resolve('./polyfills'),
		require.resolve('react-dev-utils/webpackHotDevClient'),
		paths.appSrc + '/index.js',
	],
	login: [
		require.resolve('./polyfills'),
		require.resolve('react-dev-utils/webpackHotDevClient'),
		paths.appSrc + '/login.js',
	],
	register: [
		require.resolve('./polyfills'),
		require.resolve('react-dev-utils/webpackHotDevClient'),
		paths.appSrc + '/register.js',
	],
	main: [
		require.resolve('./polyfills'),
		require.resolve('react-dev-utils/webpackHotDevClient'),
		paths.appSrc + '/main.js',
	]
}复制代码

output配置(定位:module.exports->output)

webpack.config.dev.js

output: {
	// Add /* filename */ comments to generated require()s in the output.
	pathinfo: true,
	// This does not produce a real file. It's just the virtual path that is
	// served by WebpackDevServer in development. This is the JS bundle
	// containing code from all our entry points, and the Webpack runtime.
	// created by lyb 2019/08/03
	// filename: 'static/js/bundle.js' -> filename: 'static/js/[name].js'
	// 前者对应只有一个entry,后者对应多个entry,如果不改会报错
	filename: 'static/js/[name].js',
	// There are also additional JS chunk files if you use code splitting.
	chunkFilename: 'static/js/[name].chunk.js',
	// This is the URL that app is served from. We use "/" in development.
	publicPath: publicPath,
	// Point sourcemap entries to original disk location (format as URL on Windows)
	devtoolModuleFilenameTemplate: info =>
		path.resolve(info.absoluteResourcePath).replace(/\\/g, '/'),
}复制代码

其中,特别注意filename配置项要从原始的'static/js/bundle.js'改为'static/js/[name].js',否则会报错。

webpack.config.prod.js

output: {
	// The build folder.
	path: paths.appBuild,
	// Generated JS file names (with nested folders).
	// There will be one main bundle, and one file per asynchronous chunk.
	// We don't currently advertise code splitting but Webpack supports it.
	filename: 'static/js/[name].[chunkhash:8].js',
	chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js',
	// We inferred the "public path" (such as / or /my-project) from homepage.
	publicPath: publicPath,
	// Point sourcemap entries to original disk location (format as URL on Windows)
	devtoolModuleFilenameTemplate: info =>
		path
			.relative(paths.appSrc, info.absoluteResourcePath)
			.replace(/\\/g, '/'),
}复制代码

支持antd注入和less解析(定位:module.exports->module->rules->oneOf)

webpack.config.dev.js / webpack.config.prod.js(此处配置信息,开发环境和生产环境完全相同,定位:module.exports->module->rules->oneOf)

// Process JS with Babel.
{
	test: /\.(js|jsx|mjs)$/,
	include: paths.appSrc,
	loader: require.resolve('babel-loader'),
	options: {
		plugins: [
			[
				require.resolve('babel-plugin-named-asset-import'),
				{
					loaderMap: {
						svg: {
							ReactComponent: '@svgr/webpack?-prettier,-svgo![path]',
						},
					},
				},
			],
			// 注入antd,按需加载
			["import", {
				"libraryName": "antd",
				"libraryDirectory": "es",
				"style": true // `style: true` 会加载 less 文件
			}],
		],
		// 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,
	},
},
// "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 a plugin to extract that CSS to a file, but
// in development "style" loader enables hot editing of CSS.
{
        // eject后原始正则为/\.(css)$/,为了支持less文件,需要改为/\.(css|less)$/
	test: /\.(css|less)$/,// test: /\.(css)$/ -> test: /\.(css|less)$/,新增less格式正则
	use: [
		require.resolve('style-loader'),
		{
			loader: require.resolve('css-loader'),
			options: {
				importLoaders: 1,
			},
		},
		{
			loader: require.resolve('postcss-loader'),
			options: {
				// Necessary for external CSS imports to work
				// https://github.com/facebookincubator/create-react-app/issues/2677
				ident: 'postcss',
				plugins: () => [
					require('postcss-flexbugs-fixes'),
					autoprefixer({
						browsers: [
							'>1%',
							'last 4 versions',
							'Firefox ESR',
							'not ie < 9', // React doesn't support IE8 anyway
						],
						flexbox: 'no-2009',
					}),
				],
			},
		},
		// 引入less-loader,支持编译less文件
		{
			loader: require.resolve('less-loader'),
			options: {
				// 解决报错: Inline JavaScript is not enabled. Is it set in your options?
				javascriptEnabled: true,
                                // antd全局个性化样式配置
				modifyVars: {
					'primary-color': '#ffa726',
					'link-color': '#5e77ff'
				}
			},
		}
	],
}复制代码

plugins配置(定位:module.exports->plugins)

webpack.config.dev.js(4个入口,新增4个HtmlWebpackPlugin)

new HtmlWebpackPlugin({
    inject: true,
    template: paths.appHtml,// paths文件中定义路径
    filename: 'index.html',
    chunks: ['index']
}),
new HtmlWebpackPlugin({
    inject: true,
    template: paths.loginHtml,// paths文件中定义路径
    filename: 'login.html',
    chunks: ['login']
}),
new HtmlWebpackPlugin({
    inject: true,
    template: paths.registerHtml,// paths文件中定义路径
    filename: 'register.html',
    chunks: ['register']
}),
new HtmlWebpackPlugin({
    inject: true,
    template: paths.mainHtml,// paths文件中定义路径
    filename: 'main.html',
    chunks: ['main']
}),复制代码

webpack.config.prod.js(4个入口,新增4个HtmlWebpackPlugin,此处生产环境的配置与开发环境的稍有不同)

new HtmlWebpackPlugin({
	inject: true,
	template: paths.appHtml,// paths文件中定义路径
	filename: 'index.html',
	chunks: ['index'],// 指定chunks,分隔代码以按需加载
	minify: {
		removeComments: true,
		collapseWhitespace: true,
		removeRedundantAttributes: true,
		useShortDoctype: true,
		removeEmptyAttributes: true,
		removeStyleLinkTypeAttributes: true,
		keepClosingSlash: true,
		minifyJS: true,
		minifyCSS: true,
		minifyURLs: true,
	},
}),
new HtmlWebpackPlugin({
	inject: true,
	template: paths.loginHtml,// paths文件中定义路径
	filename: 'login.html',
	chunks: ['login'],// 指定chunks,分隔代码以按需加载
	minify: {
		removeComments: true,
		collapseWhitespace: true,
		removeRedundantAttributes: true,
		useShortDoctype: true,
		removeEmptyAttributes: true,
		removeStyleLinkTypeAttributes: true,
		keepClosingSlash: true,
		minifyJS: true,
		minifyCSS: true,
		minifyURLs: true,
	},
}),
new HtmlWebpackPlugin({
	inject: true,
	template: paths.registerHtml,// paths文件中定义路径
	filename: 'register.html',
	chunks: ['register'],// 指定chunks,分隔代码以按需加载
	minify: {
		removeComments: true,
		collapseWhitespace: true,
		removeRedundantAttributes: true,
		useShortDoctype: true,
		removeEmptyAttributes: true,
		removeStyleLinkTypeAttributes: true,
		keepClosingSlash: true,
		minifyJS: true,
		minifyCSS: true,
		minifyURLs: true,
	},
}),
new HtmlWebpackPlugin({
	inject: true,
	template: paths.mainHtml,// paths文件中定义路径
	filename: 'main.html',
	chunks: ['main'],// 指定chunks,分隔代码以按需加载
	minify: {
		removeComments: true,
		collapseWhitespace: true,
		removeRedundantAttributes: true,
		useShortDoctype: true,
		removeEmptyAttributes: true,
		removeStyleLinkTypeAttributes: true,
		keepClosingSlash: true,
		minifyJS: true,
		minifyCSS: true,
		minifyURLs: true,
	},
}),复制代码

打包

yarn build


打包成功后的文件夹目录结构

build
├─ asset-manifest.json
├─ favicon.ico
├─ index.html
├─ login.html
├─ main.html
├─ manifest.json
├─ register.html
├─ service-worker.js
└─ static
       ├─ css
       │    ├─ index.a068eaf7.css
       │    ├─ index.a068eaf7.css.map
       │    ├─ login.2ff64c8e.css
       │    ├─ login.2ff64c8e.css.map
       │    ├─ main.c8e56e47.css
       │    ├─ main.c8e56e47.css.map
       │    ├─ register.e54b83db.css
       │    └─ register.e54b83db.css.map
       ├─ js
       │    ├─ index.2c0736bd.js
       │    ├─ index.2c0736bd.js.map
       │    ├─ login.fd841272.js
       │    ├─ login.fd841272.js.map
       │    ├─ main.080a9c11.js
       │    ├─ main.080a9c11.js.map
       │    ├─ register.d2b9d5a2.js
       │    └─ register.d2b9d5a2.js.map
       └─ media
              ├─ GB_bg.c4c2913b.png
              ├─ iconfont.26b4e298.eot
              ├─ iconfont.3e355800.svg
              ├─ iconfont.5cd1f541.ttf
              ├─ img07.c2e13bab.png
              ├─ img08.22d05748.png
              └─ login_bg.165cc596.jpg复制代码

可以看到,打包成功后的文件夹目录结构主要分为以下4部分

  • html(分为index、login、register、main四个主页面)
  • css(分为4个分割区)
  • js(分为4个分割区)
  • media(静态资源:图片、字体文件等)

完整webpack配置文件

webpack.config.dev.js

'use strict';

const autoprefixer = require('autoprefixer');
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const WatchMissingNodeModulesPlugin = require('react-dev-utils/WatchMissingNodeModulesPlugin');
const eslintFormatter = require('react-dev-utils/eslintFormatter');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
const getClientEnvironment = require('./env');
const paths = require('./paths');

// Webpack uses `publicPath` to determine where the app is being served from.
// In development, we always serve from the root. This makes config easier.
const publicPath = '/';
// `publicUrl` is just like `publicPath`, but we will provide it to our app
// as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript.
// Omit trailing slash as %PUBLIC_PATH%/xyz looks better than %PUBLIC_PATH%xyz.
const publicUrl = '';
// Get environment variables to inject into our app.
const env = getClientEnvironment(publicUrl);

// This is the development configuration.
// It is focused on developer experience and fast rebuilds.
// The production configuration is different and lives in a separate file.
module.exports = {
  // You may want 'eval' instead if you prefer to see the compiled output in DevTools.
  // See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.
  devtool: '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.
  // The first two entry points enable "hot" CSS and auto-refreshes for JS.
	// created by lyb 2019/08/03
	// 单入口示例
	/*
	* entry: [
			require.resolve('./polyfills'),
			require.resolve('react-dev-utils/webpackHotDevClient'),
			paths.appSrc + '/index.js',
		]
	*
	* */
  entry: {
		// We ship a few polyfills by default:
		// require.resolve('./polyfills'),
		// Include an alternative client for WebpackDevServer. A client's job is to
		// connect to WebpackDevServer by a socket and get notified about changes.
		// When you save a file, the client will either apply hot updates (in case
		// of CSS changes), or refresh the page (in case of JS changes). When you
		// make a syntax error, this client will display a syntax error overlay.
		// Note: instead of the default WebpackDevServer client, we use a custom one
		// to bring better experience for Create React App users. You can replace
		// the line below with these two lines if you prefer the stock client:
		// require.resolve('webpack-dev-server/client') + '?/',
		// require.resolve('webpack/hot/dev-server'),
		// require.resolve('react-dev-utils/webpackHotDevClient'),
		// Finally, this is your app's code:
		// paths.appIndexJs,
		// We include the app code last so that if there is a runtime error during
		// initialization, it doesn't blow up the WebpackDevServer client, and
		// changing JS code would still trigger a refresh.
		// created by lyb 2019/08/03
		// 多入口
		index: [
			require.resolve('./polyfills'),
			require.resolve('react-dev-utils/webpackHotDevClient'),
			paths.appSrc + '/index.js',
		],
		login: [
			require.resolve('./polyfills'),
			require.resolve('react-dev-utils/webpackHotDevClient'),
			paths.appSrc + '/login.js',
		],
		register: [
			require.resolve('./polyfills'),
			require.resolve('react-dev-utils/webpackHotDevClient'),
			paths.appSrc + '/register.js',
		],
		main: [
			require.resolve('./polyfills'),
			require.resolve('react-dev-utils/webpackHotDevClient'),
			paths.appSrc + '/main.js',
		]
	},
  output: {
    // Add /* filename */ comments to generated require()s in the output.
    pathinfo: true,
    // This does not produce a real file. It's just the virtual path that is
    // served by WebpackDevServer in development. This is the JS bundle
    // containing code from all our entry points, and the Webpack runtime.
		// created by lyb 2019/08/03
		// filename: 'static/js/bundle.js' -> filename: 'static/js/[name].js'
		// 前者对应只有一个entry,后者对应多个entry,如果不改会报错
    filename: 'static/js/[name].js',
    // There are also additional JS chunk files if you use code splitting.
    chunkFilename: 'static/js/[name].chunk.js',
    // This is the URL that app is served from. We use "/" in development.
    publicPath: publicPath,
    // Point sourcemap entries to original disk location (format as URL on Windows)
    devtoolModuleFilenameTemplate: info =>
      path.resolve(info.absoluteResourcePath).replace(/\\/g, '/'),
  },
  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/facebookincubator/create-react-app/issues/253
    modules: ['node_modules', paths.appNodeModules].concat(
      // It is guaranteed to exist because we tweak it in `env.js`
      process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
    ),
    // 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/facebookincubator/create-react-app/issues/290
    // `web` extension prefixes have been added for better support
    // for React Native Web.
    extensions: ['.web.js', '.mjs', '.js', '.json', '.web.jsx', '.jsx'],
    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',
			'@': paths.appSrc
    },
    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]),
    ],
  },
  module: {
    strictExportPresence: true,
    rules: [
      // TODO: Disable require.ensure as it's not a standard language feature.
      // We are waiting for https://github.com/facebookincubator/create-react-app/issues/2176.
      // { parser: { requireEnsure: false } },

      // First, run the linter.
      // It's important to do this before Babel processes the JS.
      {
        test: /\.(js|jsx|mjs)$/,
        enforce: 'pre',
        use: [
          {
            options: {
              formatter: eslintFormatter,
              eslintPath: require.resolve('eslint'),

            },
            loader: require.resolve('eslint-loader'),
          },
        ],
        include: paths.appSrc,
      },
      {
        // "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: [
          // "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$/],
            loader: require.resolve('url-loader'),
            options: {
              limit: 10000,
              name: 'static/media/[name].[hash:8].[ext]',
            },
          },
          // Process JS with Babel.
          {
            test: /\.(js|jsx|mjs)$/,
            include: paths.appSrc,
            loader: require.resolve('babel-loader'),
            options: {
							plugins: [
								[
									require.resolve('babel-plugin-named-asset-import'),
									{
										loaderMap: {
											svg: {
												ReactComponent: '@svgr/webpack?-prettier,-svgo![path]',
											},
										},
									},
								],
								// 按需加载
								["import", {
									"libraryName": "antd",
									"libraryDirectory": "es",
									"style": true // `style: true` 会加载 less 文件
								}],
							],
              // 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,
            },
          },
          // "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 a plugin to extract that CSS to a file, but
          // in development "style" loader enables hot editing of CSS.
          {
            test: /\.(css|less)$/,// test: /\.(css)$/ -> test: /\.(css|less)$/,新增less格式正则
            use: [
              require.resolve('style-loader'),
              {
                loader: require.resolve('css-loader'),
                options: {
                  importLoaders: 1,
                },
              },
              {
                loader: require.resolve('postcss-loader'),
                options: {
                  // Necessary for external CSS imports to work
                  // https://github.com/facebookincubator/create-react-app/issues/2677
                  ident: 'postcss',
                  plugins: () => [
                    require('postcss-flexbugs-fixes'),
                    autoprefixer({
                      browsers: [
                        '>1%',
                        'last 4 versions',
                        'Firefox ESR',
                        'not ie < 9', // React doesn't support IE8 anyway
                      ],
                      flexbox: 'no-2009',
                    }),
                  ],
                },
              },
							// 编译 less 文件
							{
								loader: require.resolve('less-loader'),
								options: {
									// 解决报错: Inline JavaScript is not enabled. Is it set in your options?
									javascriptEnabled: true,
									modifyVars: {
										'primary-color': '#ffa726',
										'link-color': '#5e77ff'
									}
								},
							}
            ],
          },
          // "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 processed through "file" loader.
            // Also exclude `html` and `json` extensions so they get processed
            // by webpacks internal loaders.
            exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/],
            loader: require.resolve('file-loader'),
            options: {
              name: 'static/media/[name].[hash:8].[ext]',
            },
          },
        ],
      },
      // ** STOP ** Are you adding a new loader?
      // Make sure to add the new loader(s) before the "file" loader.
    ],
  },
  plugins: [
    // Makes some environment variables available in index.html.
    // The public URL is available as %PUBLIC_URL% in index.html, e.g.:
    // <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
    // In development, this will be an empty string.
    new InterpolateHtmlPlugin(env.raw),
    // Generates an `index.html` file with the <script> injected.
    new HtmlWebpackPlugin({
			inject: true,
			template: paths.appHtml,
			filename: 'index.html',
			chunks: ['index']
    }),
		new HtmlWebpackPlugin({
			inject: true,
			template: paths.loginHtml,
			filename: 'login.html',
			chunks: ['login']
		}),
		new HtmlWebpackPlugin({
			inject: true,
			template: paths.registerHtml,
			filename: 'register.html',
			chunks: ['register']
		}),
		new HtmlWebpackPlugin({
			inject: true,
			template: paths.mainHtml,
			filename: 'main.html',
			chunks: ['main']
		}),
    // Add module names to factory functions so they appear in browser profiler.
    new webpack.NamedModulesPlugin(),
    // Makes some environment variables available to the JS code, for example:
    // if (process.env.NODE_ENV === 'development') { ... }. See `./env.js`.
    new webpack.DefinePlugin(env.stringified),
    // This is necessary to emit hot updates (currently CSS only):
    new webpack.HotModuleReplacementPlugin(),
    // 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/facebookincubator/create-react-app/issues/240
    new CaseSensitivePathsPlugin(),
    // If you require a missing module and then `npm install` it, you still have
    // to restart the development server for Webpack to discover it. This plugin
    // makes the discovery automatic so you don't have to restart.
    // See https://github.com/facebookincubator/create-react-app/issues/186
    new WatchMissingNodeModulesPlugin(paths.appNodeModules),
    // 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(/^\.\/locale$/, /moment$/),
  ],
  // Some libraries import Node modules but don't use them in the browser.
  // Tell Webpack to provide empty mocks for them so importing them works.
  node: {
    dgram: 'empty',
    fs: 'empty',
    net: 'empty',
    tls: 'empty',
    child_process: 'empty',
  },
  // Turn off performance hints during development because we don't do any
  // splitting or minification in interest of speed. These warnings become
  // cumbersome.
  performance: {
    hints: false,
  },
};复制代码

webpack.config.prod.js

'use strict';

const autoprefixer = require('autoprefixer');
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const ManifestPlugin = require('webpack-manifest-plugin');
const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin');
const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');
const eslintFormatter = require('react-dev-utils/eslintFormatter');
const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin');
// webpack打包分析工具
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const paths = require('./paths');
const getClientEnvironment = require('./env');

// 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.
const publicPath = paths.servedPath;
// Some apps do not use client-side routing with pushState.
// For these, "homepage" can be set to "." to enable relative asset paths.
const shouldUseRelativeAssetPaths = publicPath === './';
// Source maps are resource heavy and can cause out of memory issue for large source files.
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
// `publicUrl` is just like `publicPath`, but we will provide it 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.
const publicUrl = publicPath.slice(0, -1);
// Get environment variables to inject into our app.
const env = getClientEnvironment(publicUrl);

// Assert this just to be safe.
// Development builds of React are slow and not intended for production.
if (env.stringified['process.env'].NODE_ENV !== '"production"') {
	throw new Error('Production builds must have NODE_ENV=production.');
}

// Note: defined here because it will be used more than once.
const cssFilename = 'static/css/[name].[contenthash:8].css';

// ExtractTextPlugin expects the build output to be flat.
// (See https://github.com/webpack-contrib/extract-text-webpack-plugin/issues/27)
// However, our output is structured with css, js and media folders.
// To have this structure working with relative paths, we have to use custom options.
const extractTextPluginOptions = shouldUseRelativeAssetPaths
	? // Making sure that the publicPath goes back to to build folder.
	{publicPath: Array(cssFilename.split('/').length).join('../')}
	: {};

// This is the production configuration.
// It compiles slowly and is focused on producing a fast and minimal bundle.
// The development configuration is different and lives in a separate file.
module.exports = {
	// Don't attempt to continue if there are any errors.
	bail: true,
	// We generate sourcemaps in production. This is slow but gives good results.
	// You can exclude the *.map files from the build during deployment.
	devtool: shouldUseSourceMap ? 'source-map' : false,
	// In production, we only want to load the polyfills and the app code.
	entry: {
		// We ship a few polyfills by default:
		// require.resolve('./polyfills'),
		// Include an alternative client for WebpackDevServer. A client's job is to
		// connect to WebpackDevServer by a socket and get notified about changes.
		// When you save a file, the client will either apply hot updates (in case
		// of CSS changes), or refresh the page (in case of JS changes). When you
		// make a syntax error, this client will display a syntax error overlay.
		// Note: instead of the default WebpackDevServer client, we use a custom one
		// to bring better experience for Create React App users. You can replace
		// the line below with these two lines if you prefer the stock client:
		// require.resolve('webpack-dev-server/client') + '?/',
		// require.resolve('webpack/hot/dev-server'),
		// require.resolve('react-dev-utils/webpackHotDevClient'),
		// Finally, this is your app's code:
		// paths.appIndexJs,
		// We include the app code last so that if there is a runtime error during
		// initialization, it doesn't blow up the WebpackDevServer client, and
		// changing JS code would still trigger a refresh.
		index: [
			require.resolve('./polyfills'),
			require.resolve('react-dev-utils/webpackHotDevClient'),
			paths.appSrc + '/index.js',
		],
		login: [
			require.resolve('./polyfills'),
			require.resolve('react-dev-utils/webpackHotDevClient'),
			paths.appSrc + '/login.js',
		],
		register: [
			require.resolve('./polyfills'),
			require.resolve('react-dev-utils/webpackHotDevClient'),
			paths.appSrc + '/register.js',
		],
		main: [
			require.resolve('./polyfills'),
			require.resolve('react-dev-utils/webpackHotDevClient'),
			paths.appSrc + '/main.js',
		]
	},
	output: {
		// The build folder.
		path: paths.appBuild,
		// Generated JS file names (with nested folders).
		// There will be one main bundle, and one file per asynchronous chunk.
		// We don't currently advertise code splitting but Webpack supports it.
		filename: 'static/js/[name].[chunkhash:8].js',
		chunkFilename: 'static/js/[name].[chunkhash:8].chunk.js',
		// We inferred the "public path" (such as / or /my-project) from homepage.
		publicPath: publicPath,
		// Point sourcemap entries to original disk location (format as URL on Windows)
		devtoolModuleFilenameTemplate: info =>
			path
				.relative(paths.appSrc, info.absoluteResourcePath)
				.replace(/\\/g, '/'),
	},
	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/facebookincubator/create-react-app/issues/253
		modules: ['node_modules', paths.appNodeModules].concat(
			// It is guaranteed to exist because we tweak it in `env.js`
			process.env.NODE_PATH.split(path.delimiter).filter(Boolean)
		),
		// 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/facebookincubator/create-react-app/issues/290
		// `web` extension prefixes have been added for better support
		// for React Native Web.
		extensions: ['.web.js', '.mjs', '.js', '.json', '.web.jsx', '.jsx'],
		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',
			'@': paths.appSrc
		},
		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]),
		],
	},
	module: {
		strictExportPresence: true,
		rules: [
			// TODO: Disable require.ensure as it's not a standard language feature.
			// We are waiting for https://github.com/facebookincubator/create-react-app/issues/2176.
			// { parser: { requireEnsure: false } },

			// First, run the linter.
			// It's important to do this before Babel processes the JS.
			{
				test: /\.(js|jsx|mjs)$/,
				enforce: 'pre',
				use: [
					{
						options: {
							formatter: eslintFormatter,
							eslintPath: require.resolve('eslint'),

						},
						loader: require.resolve('eslint-loader'),
					},
				],
				include: paths.appSrc,
			},
			{
				// "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: [
					// "url" loader works just like "file" loader but it also embeds
					// assets smaller than specified size as data URLs to avoid requests.
					{
						test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
						loader: require.resolve('url-loader'),
						options: {
							limit: 10000,
							name: 'static/media/[name].[hash:8].[ext]',
						},
					},
					// Process JS with Babel.
					{
						test: /\.(js|jsx|mjs)$/,
						include: paths.appSrc,
						loader: require.resolve('babel-loader'),
						options: {
							plugins: [
								[
									require.resolve('babel-plugin-named-asset-import'),
									{
										loaderMap: {
											svg: {
												ReactComponent: '@svgr/webpack?-prettier,-svgo![path]',
											},
										},
									},
								],
								// 按需加载
								["import", {
									"libraryName": "antd",
									"libraryDirectory": "es",
									"style": true // `style: true` 会加载 less 文件
								}],
							],
							compact: true,
						},
					},
					// The notation here is somewhat confusing.
					// "postcss" loader applies autoprefixer to our CSS.
					// "css" loader resolves paths in CSS and adds assets as dependencies.
					// "style" loader normally turns CSS into JS modules injecting <style>,
					// but unlike in development configuration, we do something different.
					// `ExtractTextPlugin` first applies the "postcss" and "css" loaders
					// (second argument), then grabs the result CSS and puts it into a
					// separate file in our build process. This way we actually ship
					// a single CSS file in production instead of JS code injecting <style>
					// tags. If you use code splitting, however, any async bundles will still
					// use the "style" loader inside the async code so CSS from them won't be
					// in the main CSS file.
					{
						test: /\.(css|less)$/,
						loader: ExtractTextPlugin.extract(
							Object.assign(
								{
									fallback: {
										loader: require.resolve('style-loader'),
										options: {
											hmr: false,
										},
									},
									use: [
										{
											loader: require.resolve('css-loader'),
											options: {
												importLoaders: 1,
												minimize: true,
												sourceMap: shouldUseSourceMap,
											},
										},
										{
											loader: require.resolve('postcss-loader'),
											options: {
												// Necessary for external CSS imports to work
												// https://github.com/facebookincubator/create-react-app/issues/2677
												ident: 'postcss',
												plugins: () => [
													require('postcss-flexbugs-fixes'),
													autoprefixer({
														browsers: [
															'>1%',
															'last 4 versions',
															'Firefox ESR',
															'not ie < 9', // React doesn't support IE8 anyway
														],
														flexbox: 'no-2009',
													}),
												],
											},
										},
										// 编译 less 文件
										{
											loader: require.resolve('less-loader'),
											options: {
												// 解决报错: Inline JavaScript is not enabled. Is it set in your options?
												javascriptEnabled: true,
												modifyVars: {
													'primary-color': '#ffa726',
													'link-color': '#5e77ff'
												}
											},
										}
									],
								},
								extractTextPluginOptions
							)
						),
						// Note: this won't work without `new ExtractTextPlugin()` in `plugins`.
					},
					// "file" loader makes sure assets end up in the `build` folder.
					// When you `import` an asset, you get its filename.
					// This loader doesn't use a "test" so it will catch all modules
					// that fall through the other loaders.
					{
						loader: require.resolve('file-loader'),
						// Exclude `js` files to keep "css" loader working as it injects
						// it's runtime that would otherwise processed through "file" loader.
						// Also exclude `html` and `json` extensions so they get processed
						// by webpacks internal loaders.
						exclude: [/\.(js|jsx|mjs)$/, /\.html$/, /\.json$/],
						options: {
							name: 'static/media/[name].[hash:8].[ext]',
						},
					},
					// ** STOP ** Are you adding a new loader?
					// Make sure to add the new loader(s) before the "file" loader.
				],
			},
		],
	},
	plugins: [
		// Makes some environment variables available in index.html.
		// The public URL is available as %PUBLIC_URL% in index.html, e.g.:
		// <link rel="shortcut icon" href="%PUBLIC_URL%/favicon.ico">
		// In production, 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(env.raw),
		new BundleAnalyzerPlugin(),
		// Generates an `index.html` file with the <script> injected.
		new HtmlWebpackPlugin({
			inject: true,
			template: paths.appHtml,
			filename: 'index.html',
			chunks: ['index'],
			minify: {
				removeComments: true,
				collapseWhitespace: true,
				removeRedundantAttributes: true,
				useShortDoctype: true,
				removeEmptyAttributes: true,
				removeStyleLinkTypeAttributes: true,
				keepClosingSlash: true,
				minifyJS: true,
				minifyCSS: true,
				minifyURLs: true,
			},
		}),
		new HtmlWebpackPlugin({
			inject: true,
			template: paths.loginHtml,
			filename: 'login.html',
			chunks: ['login'],
			minify: {
				removeComments: true,
				collapseWhitespace: true,
				removeRedundantAttributes: true,
				useShortDoctype: true,
				removeEmptyAttributes: true,
				removeStyleLinkTypeAttributes: true,
				keepClosingSlash: true,
				minifyJS: true,
				minifyCSS: true,
				minifyURLs: true,
			},
		}),
		new HtmlWebpackPlugin({
			inject: true,
			template: paths.registerHtml,
			filename: 'register.html',
			chunks: ['register'],
			minify: {
				removeComments: true,
				collapseWhitespace: true,
				removeRedundantAttributes: true,
				useShortDoctype: true,
				removeEmptyAttributes: true,
				removeStyleLinkTypeAttributes: true,
				keepClosingSlash: true,
				minifyJS: true,
				minifyCSS: true,
				minifyURLs: true,
			},
		}),
		new HtmlWebpackPlugin({
			inject: true,
			template: paths.mainHtml,
			filename: 'main.html',
			chunks: ['main'],
			minify: {
				removeComments: true,
				collapseWhitespace: true,
				removeRedundantAttributes: true,
				useShortDoctype: true,
				removeEmptyAttributes: true,
				removeStyleLinkTypeAttributes: true,
				keepClosingSlash: true,
				minifyJS: true,
				minifyCSS: true,
				minifyURLs: true,
			},
		}),
		// new webpack.DllReferencePlugin({
		// 	context: '.',
		// 	manifest:require('./build/polyfill.manifest.json'),
		// }),
		// 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 was set to production here.
		// Otherwise React will be compiled in the very slow development mode.
		new webpack.DefinePlugin(env.stringified),
		// Minify the code.
		new webpack.optimize.UglifyJsPlugin({
			compress: {
				warnings: false,
				// Disabled because of an issue with Uglify breaking seemingly valid code:
				// https://github.com/facebookincubator/create-react-app/issues/2376
				// Pending further investigation:
				// https://github.com/mishoo/UglifyJS2/issues/2011
				comparisons: false,
			},
			mangle: {
				safari10: true,
			},
			output: {
				comments: false,
				// Turned on because emoji and regex is not minified properly using default
				// https://github.com/facebookincubator/create-react-app/issues/2488
				ascii_only: true,
			},
			sourceMap: shouldUseSourceMap,
		}),
		// Note: this won't work without ExtractTextPlugin.extract(..) in `loaders`.
		new ExtractTextPlugin({
			filename: cssFilename,
		}),
		// Generate a manifest file which contains a mapping of all asset filenames
		// to their corresponding output file so that tools can pick it up without
		// having to parse `index.html`.
		new ManifestPlugin({
			fileName: 'asset-manifest.json',
		}),
		// Generate a service worker script that will precache, and keep up to date,
		// the HTML & assets that are part of the Webpack build.
		new SWPrecacheWebpackPlugin({
			// By default, a cache-busting query parameter is appended to requests
			// used to populate the caches, to ensure the responses are fresh.
			// If a URL is already hashed by Webpack, then there is no concern
			// about it being stale, and the cache-busting can be skipped.
			dontCacheBustUrlsMatching: /\.\w{8}\./,
			filename: 'service-worker.js',
			logger(message) {
				if (message.indexOf('Total precache size is') === 0) {
					// This message occurs for every build and is a bit too noisy.
					return;
				}
				if (message.indexOf('Skipping static resource') === 0) {
					// This message obscures real errors so we ignore it.
					// https://github.com/facebookincubator/create-react-app/issues/2612
					return;
				}
				console.log(message);
			},
			minify: true,
			// For unknown URLs, fallback to the index page
			navigateFallback: publicUrl + '/index.html',
			// Ignores URLs starting from /__ (useful for Firebase):
			// https://github.com/facebookincubator/create-react-app/issues/2237#issuecomment-302693219
			navigateFallbackWhitelist: [/^(?!\/__).*/],
			// Don't precache sourcemaps (they're large) and build asset manifest:
			staticFileGlobsIgnorePatterns: [/\.map$/, /asset-manifest\.json$/],
		}),
		// 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(/^\.\/locale$/, /moment$/),
	],
	// Some libraries import Node modules but don't use them in the browser.
	// Tell Webpack to provide empty mocks for them so importing them works.
	node: {
		dgram: 'empty',
		fs: 'empty',
		net: 'empty',
		tls: 'empty',
		child_process: 'empty',
	},
};复制代码

paths.js

'use strict';

const path = require('path');
const fs = require('fs');
const url = require('url');

// Make sure any symlinks in the project folder are resolved:
// https://github.com/facebookincubator/create-react-app/issues/637
const appDirectory = fs.realpathSync(process.cwd());
const resolveApp = relativePath => path.resolve(appDirectory, relativePath);

const envPublicUrl = process.env.PUBLIC_URL;

function ensureSlash(path, needsSlash) {
	const hasSlash = path.endsWith('/');
	if (hasSlash && !needsSlash) {
		return path.substr(path, path.length - 1);
	} else if (!hasSlash && needsSlash) {
		return `${path}/`;
	} else {
		return path;
	}
}

const getPublicUrl = appPackageJson =>
	envPublicUrl || require(appPackageJson).homepage;

// We use `PUBLIC_URL` environment variable or "homepage" field to infer
// "public path" at which the app is served.
// Webpack needs to know it to put the right <script> hrefs into HTML even in
// single-page apps that may serve index.html for nested URLs like /todos/42.
// We can't use a relative path in HTML because we don't want to load something
// like /todos/42/static/js/bundle.7289d.js. We have to know the root.
function getServedPath(appPackageJson) {
	const publicUrl = getPublicUrl(appPackageJson);
	const servedUrl =
		envPublicUrl || (publicUrl ? url.parse(publicUrl).pathname : '/');
	return ensureSlash(servedUrl, true);
}

// config after eject: we're in ./config/
module.exports = {
	dotenv: resolveApp('.env'),
	appBuild: resolveApp('build'),
	appPublic: resolveApp('public'),
	appHtml: resolveApp('public/index.html'),
	loginHtml: resolveApp('public/login.html'),
	registerHtml: resolveApp('public/register.html'),
	mainHtml: resolveApp('public/main.html'),
	appIndexJs: resolveApp('src/index.js'),
	appPackageJson: resolveApp('package.json'),
	appSrc: resolveApp('src'),
	yarnLockFile: resolveApp('yarn.lock'),
	testsSetup: resolveApp('src/setupTests.js'),
	appNodeModules: resolveApp('node_modules'),
	publicUrl: getPublicUrl(resolveApp('package.json')),
	servedPath: getServedPath(resolveApp('package.json')),
};复制代码


分类:
前端
标签:
分类:
前端
标签:
收藏成功!
已添加到「」, 点击更改