Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

serve bundles and app under homepage path #1887

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion packages/create-react-app/createReactApp.js
Original file line number Diff line number Diff line change
Expand Up @@ -481,7 +481,10 @@ function getPackageName(installPackage) {
);
} else if (installPackage.match(/^file:/)) {
const installPackagePath = installPackage.match(/^file:(.*)?$/)[1];
const installPackageJson = require(path.join(installPackagePath, 'package.json'));
const installPackageJson = require(path.join(
installPackagePath,
'package.json'
));
return Promise.resolve(installPackageJson.name);
}
return Promise.resolve(installPackage);
Expand Down
2 changes: 1 addition & 1 deletion packages/react-dev-utils/FileSizeReporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ function printFileSizesAfterBuild(
name: path.basename(asset.name),
size: size,
sizeLabel:
filesize(size) + (difference ? ' (' + difference + ')' : '')
filesize(size) + (difference ? ' (' + difference + ')' : ''),
};
})
)
Expand Down
8 changes: 4 additions & 4 deletions packages/react-dev-utils/WebpackDevServerUtils.js
Original file line number Diff line number Diff line change
Expand Up @@ -34,20 +34,20 @@ if (isSmokeTest) {
};
}

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 === '::';
Expand Down Expand Up @@ -318,7 +318,7 @@ function prepareProxy(proxy, appPublicFolder) {
// However we also want to respect `proxy` for API calls.
// So if `proxy` is specified as a string, we need to decide which fallback to use.
// We use a heuristic: We want to proxy all the requests that are not meant
// for static assets and as all the requests for static assets will be using
// for static assets and as all the requests for static assets will be using
// `GET` method, we can proxy all non-`GET` requests.
// For `GET` requests, if request `accept`s text/html, we pick /index.html.
// Modern browsers include text/html into `accept` header when navigating.
Expand Down
4 changes: 3 additions & 1 deletion packages/react-dev-utils/clearConsole.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,9 @@
'use strict';

function clearConsole() {
process.stdout.write(process.platform === 'win32' ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H');
process.stdout.write(
process.platform === 'win32' ? '\x1B[2J\x1B[0f' : '\x1B[2J\x1B[3J\x1B[H'
);
}

module.exports = clearConsole;
4 changes: 2 additions & 2 deletions packages/react-dev-utils/errorOverlayMiddleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@
const launchEditor = require('./launchEditor');
const launchEditorEndpoint = require('./launchEditorEndpoint');

module.exports = function createLaunchEditorMiddleware() {
module.exports = function createLaunchEditorMiddleware(servedPathPathname) {
return function launchEditorMiddleware(req, res, next) {
if (req.url.startsWith(launchEditorEndpoint)) {
if (req.url.startsWith(`${servedPathPathname}${launchEditorEndpoint}`)) {
const lineNumber = parseInt(req.query.lineNumber, 10) || 1;
const colNumber = parseInt(req.query.colNumber, 10) || 1;
launchEditor(req.query.fileName, lineNumber, colNumber);
Expand Down
4 changes: 3 additions & 1 deletion packages/react-dev-utils/getProcessForPort.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,9 @@ function getProcessCommand(processId, processDirectory) {

function getDirectoryOfProcessById(processId) {
return execSync(
'lsof -p ' + processId + ' | awk \'$4=="cwd" {for (i=9; i<=NF; i++) printf "%s ", $i}\'',
'lsof -p ' +
processId +
' | awk \'$4=="cwd" {for (i=9; i<=NF; i++) printf "%s ", $i}\'',
execOptions
).trim();
}
Expand Down
3 changes: 1 addition & 2 deletions packages/react-dev-utils/launchEditor.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,8 +56,7 @@ const COMMON_EDITORS_OSX = {
'/Applications/RubyMine.app/Contents/MacOS/rubymine',
'/Applications/WebStorm.app/Contents/MacOS/webstorm':
'/Applications/WebStorm.app/Contents/MacOS/webstorm',
'/Applications/MacVim.app/Contents/MacOS/MacVim':
'mvim',
'/Applications/MacVim.app/Contents/MacOS/MacVim': 'mvim',
};

const COMMON_EDITORS_LINUX = {
Expand Down
6 changes: 4 additions & 2 deletions packages/react-dev-utils/noopServiceWorkerMiddleware.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,11 @@

'use strict';

module.exports = function createNoopServiceWorkerMiddleware() {
module.exports = function createNoopServiceWorkerMiddleware(
servedPathPathname
) {
return function noopServiceWorkerMiddleware(req, res, next) {
if (req.url === '/service-worker.js') {
if (req.url === `${servedPathPathname}/service-worker.js`) {
res.setHeader('Content-Type', 'text/javascript');
res.send(
`// This service worker file is effectively a 'no-op' that will reset any
Expand Down
1 change: 1 addition & 0 deletions packages/react-dev-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
"crossSpawn.js",
"eslintFormatter.js",
"errorOverlayMiddleware.js",
"serveAppMiddleware.js",
"FileSizeReporter.js",
"printBuildError.js",
"formatWebpackMessages.js",
Expand Down
23 changes: 23 additions & 0 deletions packages/react-dev-utils/serveAppMiddleware.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
'use strict';

module.exports = function createServeAppMiddleware(servedPathPathname) {
return function serveAppMiddleware(req, res, next) {
if (servedPathPathname.length > 1 && servedPathPathname !== './') {
if (req.url.indexOf(servedPathPathname) === -1) {
res.redirect(servedPathPathname);
} else {
next();
}
} else {
next();
}
};
};
15 changes: 10 additions & 5 deletions packages/react-scripts/config/webpack.config.dev.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

const autoprefixer = require('autoprefixer');
const path = require('path');
const url = require('url');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CaseSensitivePathsPlugin = require('case-sensitive-paths-webpack-plugin');
Expand All @@ -21,15 +22,18 @@ 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 = '/';
// In development, we serve from the root by default. Webpack will serve from
// the relative path of the homepage field if specified.
let publicPath = url.parse(paths.servedPath).pathname || '';
if (publicPath === './') {
publicPath = publicPath.slice(1);
}
// `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 = '';
const publicUrl = paths.servedPath.slice(0, -1) + '/static';
// Get environment variables to inject into our app.
const env = getClientEnvironment(publicUrl);

const env = getClientEnvironment(publicUrl === '.' ? '' : 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.
Expand Down Expand Up @@ -70,6 +74,7 @@ module.exports = {
// 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.
// If there is a homepage path defined, it will be served from that instead.
publicPath: publicPath,
// Point sourcemap entries to original disk location (format as URL on Windows)
devtoolModuleFilenameTemplate: info =>
Expand Down
15 changes: 13 additions & 2 deletions packages/react-scripts/config/webpackDevServer.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,18 @@

const errorOverlayMiddleware = require('react-dev-utils/errorOverlayMiddleware');
const noopServiceWorkerMiddleware = require('react-dev-utils/noopServiceWorkerMiddleware');
const serveAppMiddleware = require('react-dev-utils/serveAppMiddleware');
const ignoredFiles = require('react-dev-utils/ignoredFiles');
const url = require('url');
const config = require('./webpack.config.dev');
const paths = require('./paths');
const express = require('express');

const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const host = process.env.HOST || '0.0.0.0';

const servedPathPathname = url.parse(paths.servedPath).pathname || '';

module.exports = function(proxy, allowedHost) {
return {
// WebpackDevServer 2.4.3 introduced a security fix that prevents remote
Expand Down Expand Up @@ -86,18 +91,24 @@ module.exports = function(proxy, allowedHost) {
// Paths with dots should still use the history fallback.
// See https://github.com/facebookincubator/create-react-app/issues/387.
disableDotRule: true,
index: servedPathPathname,
},
public: allowedHost,
proxy,
before(app) {
// This lets us open files from the runtime error overlay.
app.use(errorOverlayMiddleware());
app.use(errorOverlayMiddleware(servedPathPathname));
// 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/facebookincubator/create-react-app/issues/2272#issuecomment-302832432
app.use(noopServiceWorkerMiddleware());
app.use(noopServiceWorkerMiddleware(servedPathPathname));
app.use(serveAppMiddleware(servedPathPathname));
app.use(
`${config.output.publicPath.slice(0, -1)}/static`,
express.static(paths.appPublic)
);
},
};
};
5 changes: 4 additions & 1 deletion packages/react-scripts/scripts/start.js
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ process.on('unhandledRejection', err => {
require('../config/env');

const fs = require('fs');
const url = require('url');
const chalk = require('chalk');
const webpack = require('webpack');
const WebpackDevServer = require('webpack-dev-server');
Expand Down Expand Up @@ -51,6 +52,8 @@ if (!checkRequiredFiles([paths.appHtml, paths.appIndexJs])) {
const DEFAULT_PORT = parseInt(process.env.PORT, 10) || 3000;
const HOST = process.env.HOST || '0.0.0.0';

const servedPathPathname = url.parse(paths.servedPath).pathname || '';

if (process.env.HOST) {
console.log(
chalk.cyan(
Expand All @@ -76,7 +79,7 @@ choosePort(HOST, DEFAULT_PORT)
}
const protocol = process.env.HTTPS === 'true' ? 'https' : 'http';
const appName = require(paths.appPackageJson).name;
const urls = prepareUrls(protocol, HOST, port);
const urls = prepareUrls(protocol, HOST, port, servedPathPathname);
// Create a webpack compiler that is configured with custom messages.
const compiler = createCompiler(webpack, config, appName, urls, useYarn);
// Load proxy config
Expand Down
11 changes: 9 additions & 2 deletions packages/react-scripts/template/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -300,7 +300,7 @@ In the WebStorm menu `Run` select `Edit Configurations...`. Then click `+` and s

Start your app by running `npm start`, then press `^D` on macOS or `F9` on Windows and Linux or click the green debug icon to start debugging in WebStorm.

The same way you can debug your application in IntelliJ IDEA Ultimate, PhpStorm, PyCharm Pro, and RubyMine.
The same way you can debug your application in IntelliJ IDEA Ultimate, PhpStorm, PyCharm Pro, and RubyMine.

## Formatting Code Automatically

Expand Down Expand Up @@ -1989,7 +1989,7 @@ If you’re using [Apache HTTP Server](https://httpd.apache.org/), you need to c
RewriteRule ^ index.html [QSA,L]
```

It will get copied to the `build` folder when you run `npm run build`.
It will get copied to the `build` folder when you run `npm run build`.

If you’re using [Apache Tomcat](http://tomcat.apache.org/), you need to follow [this Stack Overflow answer](https://stackoverflow.com/a/41249464/4878474).

Expand Down Expand Up @@ -2021,6 +2021,13 @@ To override this, specify the `homepage` in your `package.json`, for example:

This will let Create React App correctly infer the root path to use in the generated HTML file.

If `homepage` is specified, Create React App will open your browser at the path specified. From the example above, `npm start` would result in:

```js
http://localhost:3000/relativepath
```
This also means that in development the paths to the static files will be served out of the `relativepath` directory.

**Note**: If you are using `react-router@^4`, you can root `<Link>`s using the `basename` prop on any `<Router>`.<br>
More information [here](https://reacttraining.com/react-router/web/api/BrowserRouter/basename-string).<br>
<br>
Expand Down