mirror of
https://github.com/zhigang1992/create-react-app.git
synced 2026-06-19 17:53:49 +08:00
feat(react-scripts): allow PUBLIC_URL in develoment mode (#7259)
Co-authored-by: Eric Clemmons <eric@smarterspam.com> Co-authored-by: Alex Guerra <alex@heyimalex.com> Co-authored-by: Kelly <kelly.milligan@gmail.com> Co-authored-by: Eric Clemmons <eric@smarterspam.com> Co-authored-by: Alex Guerra <alex@heyimalex.com> Co-authored-by: Kelly <kelly.milligan@gmail.com>
This commit is contained in:
@@ -17,7 +17,7 @@ You can adjust various development and production settings by setting environmen
|
||||
| WDS_SOCKET_HOST | ✅ Used | 🚫 Ignored | When set, Create React App will run the development server with a custom websocket hostname for hot module reloading. Normally, `webpack-dev-server` defaults to `window.location.hostname` for the SockJS hostname. You may use this variable to start local development on more than one Create React App project at a time. See [webpack-dev-server documentation](https://webpack.js.org/configuration/dev-server/#devserversockhost) for more details. |
|
||||
| WDS_SOCKET_PATH | ✅ Used | 🚫 Ignored | When set, Create React App will run the development server with a custom websocket path for hot module reloading. Normally, `webpack-dev-server` defaults to `/sockjs-node` for the SockJS pathname. You may use this variable to start local development on more than one Create React App project at a time. See [webpack-dev-server documentation](https://webpack.js.org/configuration/dev-server/#devserversockpath) for more details. |
|
||||
| WDS_SOCKET_PORT | ✅ Used | 🚫 Ignored | When set, Create React App will run the development server with a custom websocket port for hot module reloading. Normally, `webpack-dev-server` defaults to `window.location.port` for the SockJS port. You may use this variable to start local development on more than one Create React App project at a time. See [webpack-dev-server documentation](https://webpack.js.org/configuration/dev-server/#devserversockport) for more details. |
|
||||
| PUBLIC_URL | 🚫 Ignored | ✅ Used | Create React App assumes your application is hosted at the serving web server's root or a subpath as specified in [`package.json` (`homepage`)](deployment#building-for-relative-paths). Normally, Create React App ignores the hostname. You may use this variable to force assets to be referenced verbatim to the url you provide (hostname included). This may be particularly useful when using a CDN to host your application. |
|
||||
| PUBLIC_URL | ✅ Used | ✅ Used | Create React App assumes your application is hosted at the serving web server's root or a subpath as specified in [`package.json` (`homepage`)](deployment#building-for-relative-paths). Normally, Create React App ignores the hostname. You may use this variable to force assets to be referenced verbatim to the url you provide (hostname included). This may be particularly useful when using a CDN to host your application. |
|
||||
| CI | ✅ Used | ✅ Used | When set to `true`, Create React App treats warnings as failures in the build. It also makes the test runner non-watching. Most CIs set this flag by default. |
|
||||
| REACT_EDITOR | ✅ Used | 🚫 Ignored | When an app crashes in development, you will see an error overlay with clickable stack trace. When you click on it, Create React App will try to determine the editor you are using based on currently running processes, and open the relevant source file. You can [send a pull request to detect your editor of choice](https://github.com/facebook/create-react-app/issues/2636). Setting this environment variable overrides the automatic detection. If you do it, make sure your systems [PATH](<https://en.wikipedia.org/wiki/PATH_(variable)>) environment variable points to your editor’s bin folder. You can also set it to `none` to disable it completely. |
|
||||
| CHOKIDAR_USEPOLLING | ✅ Used | 🚫 Ignored | When set to `true`, the watcher runs in polling mode, as necessary inside a VM. Use this option if `npm start` isn't detecting changes. |
|
||||
|
||||
@@ -287,9 +287,14 @@ getProcessForPort(3000);
|
||||
|
||||
On macOS, tries to find a known running editor process and opens the file in it. It can also be explicitly configured by `REACT_EDITOR`, `VISUAL`, or `EDITOR` environment variables. For example, you can put `REACT_EDITOR=atom` in your `.env.local` file, and Create React App will respect that.
|
||||
|
||||
#### `noopServiceWorkerMiddleware(): ExpressMiddleware`
|
||||
#### `noopServiceWorkerMiddleware(servedPath: string): ExpressMiddleware`
|
||||
|
||||
Returns Express middleware that serves a `/service-worker.js` that resets any previously set service worker configuration. Useful for development.
|
||||
Returns Express middleware that serves a `${servedPath}/service-worker.js` that resets any previously set service worker configuration. Useful for development.
|
||||
|
||||
#### `redirectServedPathMiddleware(servedPath: string): ExpressMiddleware`
|
||||
|
||||
Returns Express middleware that redirects to `${servedPath}/${req.path}`, if `req.url`
|
||||
does not start with `servedPath`. Useful for development.
|
||||
|
||||
#### `openBrowser(url: string): boolean`
|
||||
|
||||
@@ -314,7 +319,7 @@ Pass your parsed `package.json` object as `appPackage`, your the URL where you p
|
||||
|
||||
```js
|
||||
const appPackage = require(paths.appPackageJson);
|
||||
const publicUrl = paths.publicUrl;
|
||||
const publicUrl = paths.publicUrlOrPath;
|
||||
const publicPath = config.output.publicPath;
|
||||
printHostingInstructions(appPackage, publicUrl, publicPath, 'build', true);
|
||||
```
|
||||
@@ -344,7 +349,7 @@ The `args` object accepts a number of properties:
|
||||
|
||||
Creates a WebpackDevServer `proxy` configuration object from the `proxy` setting in `package.json`.
|
||||
|
||||
##### `prepareUrls(protocol: string, host: string, port: number): Object`
|
||||
##### `prepareUrls(protocol: string, host: string, port: number, pathname: string = '/'): Object`
|
||||
|
||||
Returns an object with local and remote URLs for the development server. Pass this object to `createCompiler()` described above.
|
||||
|
||||
|
||||
@@ -22,20 +22,20 @@ const forkTsCheckerWebpackPlugin = require('./ForkTsCheckerWebpackPlugin');
|
||||
|
||||
const isInteractive = process.stdout.isTTY;
|
||||
|
||||
function prepareUrls(protocol, host, port) {
|
||||
function prepareUrls(protocol, host, port, pathname = '/') {
|
||||
const formatUrl = hostname =>
|
||||
url.format({
|
||||
protocol,
|
||||
hostname,
|
||||
port,
|
||||
pathname: '/',
|
||||
pathname,
|
||||
});
|
||||
const prettyPrintUrl = hostname =>
|
||||
url.format({
|
||||
protocol,
|
||||
hostname,
|
||||
port: chalk.bold(port),
|
||||
pathname: '/',
|
||||
pathname,
|
||||
});
|
||||
|
||||
const isUnspecifiedHost = host === '0.0.0.0' || host === '::';
|
||||
|
||||
128
packages/react-dev-utils/__tests__/getPublicUrlOrPath.test.js
Normal file
128
packages/react-dev-utils/__tests__/getPublicUrlOrPath.test.js
Normal file
@@ -0,0 +1,128 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const getPublicUrlOrPath = require('../getPublicUrlOrPath');
|
||||
|
||||
const tests = [
|
||||
// DEVELOPMENT with homepage
|
||||
{ dev: true, homepage: '/', expect: '/' },
|
||||
{ dev: true, homepage: '/test', expect: '/test/' },
|
||||
{ dev: true, homepage: '/test/', expect: '/test/' },
|
||||
{ dev: true, homepage: './', expect: '/' },
|
||||
{ dev: true, homepage: '../', expect: '/' },
|
||||
{ dev: true, homepage: '../test', expect: '/' },
|
||||
{ dev: true, homepage: './test/path', expect: '/' },
|
||||
{ dev: true, homepage: 'https://create-react-app.dev/', expect: '/' },
|
||||
{
|
||||
dev: true,
|
||||
homepage: 'https://create-react-app.dev/test',
|
||||
expect: '/test/',
|
||||
},
|
||||
// DEVELOPMENT with publicURL
|
||||
{ dev: true, publicUrl: '/', expect: '/' },
|
||||
{ dev: true, publicUrl: '/test', expect: '/test/' },
|
||||
{ dev: true, publicUrl: '/test/', expect: '/test/' },
|
||||
{ dev: true, publicUrl: './', expect: '/' },
|
||||
{ dev: true, publicUrl: '../', expect: '/' },
|
||||
{ dev: true, publicUrl: '../test', expect: '/' },
|
||||
{ dev: true, publicUrl: './test/path', expect: '/' },
|
||||
{ dev: true, publicUrl: 'https://create-react-app.dev/', expect: '/' },
|
||||
{
|
||||
dev: true,
|
||||
publicUrl: 'https://create-react-app.dev/test',
|
||||
expect: '/test/',
|
||||
},
|
||||
// DEVELOPMENT with publicURL and homepage
|
||||
{ dev: true, publicUrl: '/', homepage: '/test', expect: '/' },
|
||||
{ dev: true, publicUrl: '/test', homepage: '/path', expect: '/test/' },
|
||||
{ dev: true, publicUrl: '/test/', homepage: '/test/path', expect: '/test/' },
|
||||
{ dev: true, publicUrl: './', homepage: '/test', expect: '/' },
|
||||
{ dev: true, publicUrl: '../', homepage: '/test', expect: '/' },
|
||||
{ dev: true, publicUrl: '../test', homepage: '/test', expect: '/' },
|
||||
{ dev: true, publicUrl: './test/path', homepage: '/test', expect: '/' },
|
||||
{
|
||||
dev: true,
|
||||
publicUrl: 'https://create-react-app.dev/',
|
||||
homepage: '/test',
|
||||
expect: '/',
|
||||
},
|
||||
{
|
||||
dev: true,
|
||||
publicUrl: 'https://create-react-app.dev/test',
|
||||
homepage: '/path',
|
||||
expect: '/test/',
|
||||
},
|
||||
|
||||
// PRODUCTION with homepage
|
||||
{ dev: false, homepage: '/', expect: '/' },
|
||||
{ dev: false, homepage: '/test', expect: '/test/' },
|
||||
{ dev: false, homepage: '/test/', expect: '/test/' },
|
||||
{ dev: false, homepage: './', expect: './' },
|
||||
{ dev: false, homepage: '../', expect: '../' },
|
||||
{ dev: false, homepage: '../test', expect: '../test/' },
|
||||
{ dev: false, homepage: './test/path', expect: './test/path/' },
|
||||
{ dev: false, homepage: 'https://create-react-app.dev/', expect: '/' },
|
||||
{
|
||||
dev: false,
|
||||
homepage: 'https://create-react-app.dev/test',
|
||||
expect: '/test/',
|
||||
},
|
||||
// PRODUCTION with publicUrl
|
||||
{ dev: false, publicUrl: '/', expect: '/' },
|
||||
{ dev: false, publicUrl: '/test', expect: '/test/' },
|
||||
{ dev: false, publicUrl: '/test/', expect: '/test/' },
|
||||
{ dev: false, publicUrl: './', expect: './' },
|
||||
{ dev: false, publicUrl: '../', expect: '../' },
|
||||
{ dev: false, publicUrl: '../test', expect: '../test/' },
|
||||
{ dev: false, publicUrl: './test/path', expect: './test/path/' },
|
||||
{
|
||||
dev: false,
|
||||
publicUrl: 'https://create-react-app.dev/',
|
||||
expect: 'https://create-react-app.dev/',
|
||||
},
|
||||
{
|
||||
dev: false,
|
||||
publicUrl: 'https://create-react-app.dev/test',
|
||||
expect: 'https://create-react-app.dev/test/',
|
||||
},
|
||||
// PRODUCTION with publicUrl and homepage
|
||||
{ dev: false, publicUrl: '/', homepage: '/test', expect: '/' },
|
||||
{ dev: false, publicUrl: '/test', homepage: '/path', expect: '/test/' },
|
||||
{ dev: false, publicUrl: '/test/', homepage: '/test/path', expect: '/test/' },
|
||||
{ dev: false, publicUrl: './', homepage: '/test', expect: './' },
|
||||
{ dev: false, publicUrl: '../', homepage: '/test', expect: '../' },
|
||||
{ dev: false, publicUrl: '../test', homepage: '/test', expect: '../test/' },
|
||||
{
|
||||
dev: false,
|
||||
publicUrl: './test/path',
|
||||
homepage: '/test',
|
||||
expect: './test/path/',
|
||||
},
|
||||
{
|
||||
dev: false,
|
||||
publicUrl: 'https://create-react-app.dev/',
|
||||
homepage: '/test',
|
||||
expect: 'https://create-react-app.dev/',
|
||||
},
|
||||
{
|
||||
dev: false,
|
||||
publicUrl: 'https://create-react-app.dev/test',
|
||||
homepage: '/path',
|
||||
expect: 'https://create-react-app.dev/test/',
|
||||
},
|
||||
];
|
||||
|
||||
describe('getPublicUrlOrPath', () => {
|
||||
tests.forEach(t =>
|
||||
it(JSON.stringify(t), () => {
|
||||
const actual = getPublicUrlOrPath(t.dev, t.homepage, t.publicUrl);
|
||||
expect(actual).toBe(t.expect);
|
||||
})
|
||||
);
|
||||
});
|
||||
65
packages/react-dev-utils/getPublicUrlOrPath.js
vendored
Normal file
65
packages/react-dev-utils/getPublicUrlOrPath.js
vendored
Normal file
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
|
||||
'use strict';
|
||||
|
||||
const { URL } = require('url');
|
||||
|
||||
module.exports = getPublicUrlOrPath;
|
||||
|
||||
/**
|
||||
* Returns a URL or a path with slash at the end
|
||||
* In production can be URL, abolute path, relative path
|
||||
* In development always will be an absolute path
|
||||
* In development can use `path` module functions for operations
|
||||
*
|
||||
* @param {boolean} isEnvDevelopment
|
||||
* @param {(string|undefined)} homepage a valid url or pathname
|
||||
* @param {(string|undefined)} envPublicUrl a valid url or pathname
|
||||
* @returns {string}
|
||||
*/
|
||||
function getPublicUrlOrPath(isEnvDevelopment, homepage, envPublicUrl) {
|
||||
const stubDomain = 'https://create-react-app.dev';
|
||||
|
||||
if (envPublicUrl) {
|
||||
// ensure last slash exists
|
||||
envPublicUrl = envPublicUrl.endsWith('/')
|
||||
? envPublicUrl
|
||||
: envPublicUrl + '/';
|
||||
|
||||
// validate if `envPublicUrl` is a URL or path like
|
||||
// `stubDomain` is ignored if `envPublicUrl` contains a domain
|
||||
const validPublicUrl = new URL(envPublicUrl, stubDomain);
|
||||
|
||||
return isEnvDevelopment
|
||||
? envPublicUrl.startsWith('.')
|
||||
? '/'
|
||||
: validPublicUrl.pathname
|
||||
: // Some apps do not use client-side routing with pushState.
|
||||
// For these, "homepage" can be set to "." to enable relative asset paths.
|
||||
envPublicUrl;
|
||||
}
|
||||
|
||||
if (homepage) {
|
||||
// strip last slash if exists
|
||||
homepage = homepage.endsWith('/') ? homepage : homepage + '/';
|
||||
|
||||
// validate if `homepage` is a URL or path like and use just pathname
|
||||
const validHomepagePathname = new URL(homepage, stubDomain).pathname;
|
||||
return isEnvDevelopment
|
||||
? homepage.startsWith('.')
|
||||
? '/'
|
||||
: validHomepagePathname
|
||||
: // Some apps do not use client-side routing with pushState.
|
||||
// For these, "homepage" can be set to "." to enable relative asset paths.
|
||||
homepage.startsWith('.')
|
||||
? homepage
|
||||
: validHomepagePathname;
|
||||
}
|
||||
|
||||
return '/';
|
||||
}
|
||||
@@ -7,9 +7,11 @@
|
||||
|
||||
'use strict';
|
||||
|
||||
module.exports = function createNoopServiceWorkerMiddleware() {
|
||||
const path = require('path');
|
||||
|
||||
module.exports = function createNoopServiceWorkerMiddleware(servedPath) {
|
||||
return function noopServiceWorkerMiddleware(req, res, next) {
|
||||
if (req.url === '/service-worker.js') {
|
||||
if (req.url === path.join(servedPath, 'service-worker.js')) {
|
||||
res.setHeader('Content-Type', 'text/javascript');
|
||||
res.send(
|
||||
`// This service worker file is effectively a 'no-op' that will reset any
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
"getCacheIdentifier.js",
|
||||
"getCSSModuleLocalIdent.js",
|
||||
"getProcessForPort.js",
|
||||
"getPublicUrlOrPath.js",
|
||||
"globby.js",
|
||||
"ignoredFiles.js",
|
||||
"immer.js",
|
||||
@@ -44,6 +45,7 @@
|
||||
"openChrome.applescript",
|
||||
"printBuildError.js",
|
||||
"printHostingInstructions.js",
|
||||
"redirectServedPathMiddleware.js",
|
||||
"typescriptFormatter.js",
|
||||
"WatchMissingNodeModulesPlugin.js",
|
||||
"WebpackDevServerUtils.js",
|
||||
|
||||
26
packages/react-dev-utils/redirectServedPathMiddleware.js
vendored
Normal file
26
packages/react-dev-utils/redirectServedPathMiddleware.js
vendored
Normal file
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* Copyright (c) 2015-present, Facebook, Inc.
|
||||
*
|
||||
* This source code is licensed under the MIT license found in the
|
||||
* LICENSE file in the root directory of this source tree.
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
const path = require('path');
|
||||
|
||||
module.exports = function createRedirectServedPathMiddleware(servedPath) {
|
||||
// remove end slash so user can land on `/test` instead of `/test/`
|
||||
servedPath = servedPath.slice(0, -1);
|
||||
return function redirectServedPathMiddleware(req, res, next) {
|
||||
if (
|
||||
servedPath === '' ||
|
||||
req.url === servedPath ||
|
||||
req.url.startsWith(servedPath)
|
||||
) {
|
||||
next();
|
||||
} else {
|
||||
const newPath = path.join(servedPath, req.path !== '/' ? req.path : '');
|
||||
res.redirect(newPath);
|
||||
}
|
||||
};
|
||||
};
|
||||
38
packages/react-scripts/config/paths.js
vendored
38
packages/react-scripts/config/paths.js
vendored
@@ -10,41 +10,24 @@
|
||||
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const url = require('url');
|
||||
const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath');
|
||||
|
||||
// Make sure any symlinks in the project folder are resolved:
|
||||
// https://github.com/facebook/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(inputPath, needsSlash) {
|
||||
const hasSlash = inputPath.endsWith('/');
|
||||
if (hasSlash && !needsSlash) {
|
||||
return inputPath.substr(0, inputPath.length - 1);
|
||||
} else if (!hasSlash && needsSlash) {
|
||||
return `${inputPath}/`;
|
||||
} else {
|
||||
return inputPath;
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
const publicUrlOrPath = getPublicUrlOrPath(
|
||||
process.env.NODE_ENV === 'development',
|
||||
require(resolveApp('package.json')).homepage,
|
||||
process.env.PUBLIC_URL
|
||||
);
|
||||
|
||||
const moduleFileExtensions = [
|
||||
'web.mjs',
|
||||
@@ -89,8 +72,7 @@ module.exports = {
|
||||
testsSetup: resolveModule(resolveApp, 'src/setupTests'),
|
||||
proxySetup: resolveApp('src/setupProxy.js'),
|
||||
appNodeModules: resolveApp('node_modules'),
|
||||
publicUrl: getPublicUrl(resolveApp('package.json')),
|
||||
servedPath: getServedPath(resolveApp('package.json')),
|
||||
publicUrlOrPath,
|
||||
};
|
||||
|
||||
// @remove-on-eject-begin
|
||||
@@ -112,8 +94,7 @@ module.exports = {
|
||||
testsSetup: resolveModule(resolveApp, 'src/setupTests'),
|
||||
proxySetup: resolveApp('src/setupProxy.js'),
|
||||
appNodeModules: resolveApp('node_modules'),
|
||||
publicUrl: getPublicUrl(resolveApp('package.json')),
|
||||
servedPath: getServedPath(resolveApp('package.json')),
|
||||
publicUrlOrPath,
|
||||
// These properties only exist before ejecting:
|
||||
ownPath: resolveOwn('.'),
|
||||
ownNodeModules: resolveOwn('node_modules'), // This is empty on npm 3
|
||||
@@ -148,8 +129,7 @@ if (
|
||||
testsSetup: resolveModule(resolveOwn, `${templatePath}/src/setupTests`),
|
||||
proxySetup: resolveOwn(`${templatePath}/src/setupProxy.js`),
|
||||
appNodeModules: resolveOwn('node_modules'),
|
||||
publicUrl: getPublicUrl(resolveOwn('package.json')),
|
||||
servedPath: getServedPath(resolveOwn('package.json')),
|
||||
publicUrlOrPath,
|
||||
// These properties only exist before ejecting:
|
||||
ownPath: resolveOwn('.'),
|
||||
ownNodeModules: resolveOwn('node_modules'),
|
||||
|
||||
@@ -70,24 +70,11 @@ module.exports = function(webpackEnv) {
|
||||
const isEnvProductionProfile =
|
||||
isEnvProduction && process.argv.includes('--profile');
|
||||
|
||||
// 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.
|
||||
// In development, we always serve from the root. This makes config easier.
|
||||
const publicPath = isEnvProduction
|
||||
? paths.servedPath
|
||||
: isEnvDevelopment && '/';
|
||||
// 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 === './';
|
||||
|
||||
// `publicUrl` is just like `publicPath`, but we will provide it to our app
|
||||
// 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.
|
||||
const publicUrl = isEnvProduction
|
||||
? publicPath.slice(0, -1)
|
||||
: isEnvDevelopment && '';
|
||||
// Get environment variables to inject into our app.
|
||||
const env = getClientEnvironment(publicUrl);
|
||||
const env = getClientEnvironment(paths.publicUrlOrPath.slice(0, -1));
|
||||
|
||||
// common function to get style loaders
|
||||
const getStyleLoaders = (cssOptions, preProcessor) => {
|
||||
@@ -95,7 +82,11 @@ module.exports = function(webpackEnv) {
|
||||
isEnvDevelopment && require.resolve('style-loader'),
|
||||
isEnvProduction && {
|
||||
loader: MiniCssExtractPlugin.loader,
|
||||
options: shouldUseRelativeAssetPaths ? { publicPath: '../../' } : {},
|
||||
// css is located in `static/css`, use '../../' to locate index.html folder
|
||||
// in production `paths.publicUrlOrPath` can be a relative path
|
||||
options: paths.publicUrlOrPath.startsWith('.')
|
||||
? { publicPath: '../../' }
|
||||
: {},
|
||||
},
|
||||
{
|
||||
loader: require.resolve('css-loader'),
|
||||
@@ -192,9 +183,10 @@ module.exports = function(webpackEnv) {
|
||||
chunkFilename: isEnvProduction
|
||||
? 'static/js/[name].[contenthash:8].chunk.js'
|
||||
: isEnvDevelopment && 'static/js/[name].chunk.js',
|
||||
// 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.
|
||||
// We use "/" in development.
|
||||
publicPath: publicPath,
|
||||
publicPath: paths.publicUrlOrPath,
|
||||
// Point sourcemap entries to original disk location (format as URL on Windows)
|
||||
devtoolModuleFilenameTemplate: isEnvProduction
|
||||
? info =>
|
||||
@@ -270,8 +262,8 @@ module.exports = function(webpackEnv) {
|
||||
: false,
|
||||
},
|
||||
cssProcessorPluginOptions: {
|
||||
preset: ['default', { minifyFontValues: { removeQuotes: false } }]
|
||||
}
|
||||
preset: ['default', { minifyFontValues: { removeQuotes: false } }],
|
||||
},
|
||||
}),
|
||||
],
|
||||
// Automatically split vendor and commons
|
||||
@@ -615,9 +607,8 @@ module.exports = function(webpackEnv) {
|
||||
// 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">
|
||||
// In production, it will be an empty string unless you specify "homepage"
|
||||
// It will be an empty string unless you specify "homepage"
|
||||
// in `package.json`, in which case it will be the pathname of that URL.
|
||||
// In development, this will be an empty string.
|
||||
new InterpolateHtmlPlugin(HtmlWebpackPlugin, env.raw),
|
||||
// This gives some necessary context to module not found errors, such as
|
||||
// the requesting resource.
|
||||
@@ -655,7 +646,7 @@ module.exports = function(webpackEnv) {
|
||||
// can be used to reconstruct the HTML if necessary
|
||||
new ManifestPlugin({
|
||||
fileName: 'asset-manifest.json',
|
||||
publicPath: publicPath,
|
||||
publicPath: paths.publicUrlOrPath,
|
||||
generate: (seed, files, entrypoints) => {
|
||||
const manifestFiles = files.reduce((manifest, file) => {
|
||||
manifest[file.name] = file.path;
|
||||
@@ -684,7 +675,7 @@ module.exports = function(webpackEnv) {
|
||||
clientsClaim: true,
|
||||
exclude: [/\.map$/, /asset-manifest\.json$/],
|
||||
importWorkboxFrom: 'cdn',
|
||||
navigateFallback: publicUrl + '/index.html',
|
||||
navigateFallback: paths.publicUrlOrPath + 'index.html',
|
||||
navigateFallbackBlacklist: [
|
||||
// Exclude URLs starting with /_, as they're likely an API call
|
||||
new RegExp('^/_'),
|
||||
|
||||
@@ -13,6 +13,7 @@ const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware')
|
||||
const evalSourceMapMiddleware = require('react-dev-utils/evalSourceMapMiddleware');
|
||||
const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware');
|
||||
const ignoredFiles = require('react-dev-utils/ignoredFiles');
|
||||
const redirectServedPath = require('react-dev-utils/redirectServedPathMiddleware');
|
||||
const paths = require('./paths');
|
||||
const getHttpsConfig = require('./getHttpsConfig');
|
||||
|
||||
@@ -61,6 +62,7 @@ module.exports = function(proxy, allowedHost) {
|
||||
// for some reason broken when imported through Webpack. If you just want to
|
||||
// use an image, put it in `src` and `import` it from JavaScript instead.
|
||||
contentBase: paths.appPublic,
|
||||
contentBasePublicPath: paths.publicUrlOrPath,
|
||||
// By default files from `contentBase` will not trigger a page reload.
|
||||
watchContentBase: true,
|
||||
// Enable hot reloading server. It will provide WDS_SOCKET_PATH endpoint
|
||||
@@ -81,9 +83,11 @@ module.exports = function(proxy, allowedHost) {
|
||||
sockHost,
|
||||
sockPath,
|
||||
sockPort,
|
||||
// It is important to tell WebpackDevServer to use the same "root" path
|
||||
// as we specified in the config. In development, we always serve from /.
|
||||
publicPath: '/',
|
||||
// It is important to tell WebpackDevServer to use the same "publicPath" path as
|
||||
// we specified in the Webpack config. When homepage is '.', default to serving
|
||||
// from the root.
|
||||
// remove last slash so user can land on `/test` instead of `/test/`
|
||||
publicPath: paths.publicUrlOrPath.slice(0, -1),
|
||||
// WebpackDevServer is noisy by default so we emit custom message instead
|
||||
// by listening to the compiler events with `compiler.hooks[...].tap` calls above.
|
||||
quiet: true,
|
||||
@@ -101,26 +105,32 @@ module.exports = function(proxy, allowedHost) {
|
||||
// Paths with dots should still use the history fallback.
|
||||
// See https://github.com/facebook/create-react-app/issues/387.
|
||||
disableDotRule: true,
|
||||
index: paths.publicUrlOrPath,
|
||||
},
|
||||
public: allowedHost,
|
||||
proxy,
|
||||
before(app, server) {
|
||||
if (fs.existsSync(paths.proxySetup)) {
|
||||
// This registers user provided middleware for proxy reasons
|
||||
require(paths.proxySetup)(app);
|
||||
}
|
||||
|
||||
// Keep `evalSourceMapMiddleware` and `errorOverlayMiddleware`
|
||||
// middlewares before `redirectServedPath` otherwise will not have any effect
|
||||
// This lets us fetch source contents from webpack for the error overlay
|
||||
app.use(evalSourceMapMiddleware(server));
|
||||
// This lets us open files from the runtime error overlay.
|
||||
app.use(errorOverlayMiddleware());
|
||||
|
||||
// Redirect to `PUBLIC_URL` or `homepage` from `package.json` if url not match
|
||||
app.use(redirectServedPath(paths.publicUrlOrPath));
|
||||
|
||||
if (fs.existsSync(paths.proxySetup)) {
|
||||
// This registers user provided middleware for proxy reasons
|
||||
require(paths.proxySetup)(app);
|
||||
}
|
||||
|
||||
// This service worker file is effectively a 'no-op' that will reset any
|
||||
// previous service worker registered for the same host:port combination.
|
||||
// We do this in development to avoid hitting the production cache if
|
||||
// it used the same host and port.
|
||||
// https://github.com/facebook/create-react-app/issues/2272#issuecomment-302832432
|
||||
app.use(noopServiceWorkerMiddleware());
|
||||
app.use(noopServiceWorkerMiddleware(paths.publicUrlOrPath));
|
||||
},
|
||||
};
|
||||
};
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
"ts-pnp": "1.1.5",
|
||||
"url-loader": "2.3.0",
|
||||
"webpack": "4.41.5",
|
||||
"webpack-dev-server": "3.10.1",
|
||||
"webpack-dev-server": "3.10.2",
|
||||
"webpack-manifest-plugin": "2.2.0",
|
||||
"workbox-webpack-plugin": "4.3.1"
|
||||
},
|
||||
|
||||
2
packages/react-scripts/scripts/build.js
vendored
2
packages/react-scripts/scripts/build.js
vendored
@@ -110,7 +110,7 @@ checkBrowsers(paths.appPath, isInteractive)
|
||||
console.log();
|
||||
|
||||
const appPackage = require(paths.appPackageJson);
|
||||
const publicUrl = paths.publicUrl;
|
||||
const publicUrl = paths.publicUrlOrPath;
|
||||
const publicPath = config.output.publicPath;
|
||||
const buildFolder = path.relative(process.cwd(), paths.appBuild);
|
||||
printHostingInstructions(
|
||||
|
||||
8
packages/react-scripts/scripts/start.js
vendored
8
packages/react-scripts/scripts/start.js
vendored
@@ -91,12 +91,18 @@ checkBrowsers(paths.appPath, isInteractive)
|
||||
// We have not found a port.
|
||||
return;
|
||||
}
|
||||
|
||||
const config = configFactory('development');
|
||||
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
|
||||
const appName = require(paths.appPackageJson).name;
|
||||
const useTypeScript = fs.existsSync(paths.appTsConfig);
|
||||
const tscCompileOnError = process.env.TSC_COMPILE_ON_ERROR === 'true';
|
||||
const urls = prepareUrls(protocol, HOST, port);
|
||||
const urls = prepareUrls(
|
||||
protocol,
|
||||
HOST,
|
||||
port,
|
||||
paths.publicUrlOrPath.slice(0, -1)
|
||||
);
|
||||
const devSocket = {
|
||||
warnings: warnings =>
|
||||
devServer.sockWrite(devServer.sockets, 'warnings', warnings),
|
||||
|
||||
Reference in New Issue
Block a user