mAAdhaTTah/brookjs

View on GitHub
packages/brookjs-cli/src/webpack/selectors.ts

Summary

Maintainability
D
2 days
Test Coverage
File `selectors.ts` has 510 lines of code (exceeds 250 allowed). Consider refactoring.
// @todo: readd NpmInstallPlugin
// @todo: clean up this file (extra functions, commented out code, etc.)
import path from 'path';
// import address from 'address';
import webpack, { Loader } from 'webpack';
import CaseSensitivePathsPlugin from 'case-sensitive-paths-webpack-plugin';
import { Plugin as ShakePlugin } from 'webpack-common-shake';
import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin';
import TerserPlugin from 'terser-webpack-plugin';
import safePostCssParser from 'postcss-safe-parser';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import postcssNormalize from 'postcss-normalize';
import getCSSModuleLocalIdent from 'react-dev-utils/getCSSModuleLocalIdent';
import errorOverlayMiddleware from 'react-dev-utils/errorOverlayMiddleware';
import evalSourceMapMiddleware from 'react-dev-utils/evalSourceMapMiddleware';
import noopServiceWorkerMiddleware from 'react-dev-utils/noopServiceWorkerMiddleware';
import ignoredFiles from 'react-dev-utils/ignoredFiles';
// import InlineChunkHtmlPlugin from 'react-dev-utils/InlineChunkHtmlPlugin';
// import InterpolateHtmlPlugin from 'react-dev-utils/InterpolateHtmlPlugin';
// import ModuleNotFoundPlugin from 'react-dev-utils/ModuleNotFoundPlugin';
// import WatchMissingNodeModulesPlugin from 'react-dev-utils/WatchMissingNodeModulesPlugin';
import ManifestPlugin from 'webpack-manifest-plugin';
import WebpackDevServer from 'webpack-dev-server';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import { unreachable } from 'brookjs-types';
import camelcase from 'camelcase';
import { BuildConfig } from './types';
// @TODO(mAAdhaTTah) fix require -> import (missing types)
// const getPublicUrlOrPath = require('react-dev-utils/getPublicUrlOrPath');
// const redirectServedPath = require('react-dev-utils/redirectServedPathMiddleware');
const ForkTsCheckerWebpackPlugin = require('react-dev-utils/ForkTsCheckerWebpackPlugin');
 
// file regexes
const jsRegex = /\.(js|mjs|jsx|ts|tsx)$/;
const cssRegex = /\.css$/;
const cssModuleRegex = /\.module\.css$/;
const sassRegex = /\.(scss|sass)$/;
const sassModuleRegex = /\.module\.(scss|sass)$/;
 
const isEnvDevelopment = (state: BuildConfig) => state.env === 'development';
const isEnvProduction = (state: BuildConfig) => state.env === 'production';
const isEnvProductionProfile = (/* state: State */) => false;
const shouldUseSourceMap = (/* state: State */) => true;
const shouldUseRelativeAssetPaths = (state: BuildConfig) =>
selectPublicPath(state) === './';
const selectPublicPath = (state: BuildConfig) => '/';
const selectPublicUrlOrPath = (state: BuildConfig) => {
return '/';
// return getPublicUrlOrPath(isEnvDevelopment(state));
};
const selectAppPath = (state: BuildConfig): string =>
path.join(state.cwd, state.rc?.dir ?? 'src');
const selectAppHtml = (state: BuildConfig) =>
path.join(state.cwd, 'public', 'index.html');
// const selectHttpsConfig = (state: State) => false;
// const selectProxy = (state: State) => undefined;
// const selectHost = (state: State) => '0.0.0.0';
// const selectAllowHosts = (state: State) => {
// const host = selectHost(state);
// const isUnspecifiedHost = host === '0.0.0.0' || host === '::';
// let lanUrlForConfig;
// if (isUnspecifiedHost) {
// try {
// // This can only return an IPv4 address
// lanUrlForConfig = address.ip();
// if (lanUrlForConfig) {
// // Check if the address is a private ip
// // https://en.wikipedia.org/wiki/Private_network#Private_IPv4_address_spaces
// if (
// !/^10[.]|^172[.](1[6-9]|2[0-9]|3[0-1])[.]|^192[.]168[.]/.test(
// lanUrlForConfig
// )
// ) {
// // Address is not private, so we will discard it
// lanUrlForConfig = undefined;
// }
// }
// } catch (_e) {
// // ignored
// }
// }
 
// return lanUrlForConfig;
// };
 
// const shouldInlineRuntimeChunk = (state: State) => true;
// const selectPublicUrl = (state: State) => {
// switch (state.cmd) {
// case 'start':
// return 'localhost:3000';
// case 'build':
// return '';
// default:
// return unreachable(state.cmd);
// }
// };
 
// const selectAppNodeModulesPath = (state: State) =>
// path.join(state.cwd, 'node_modules');
 
const defaultBabelConfig = {
presets: [require.resolve('babel-preset-brookjs')],
plugins: [
[
require.resolve('babel-plugin-named-asset-import'),
{
loaderMap: {
svg: {
ReactComponent: '@svgr/webpack?-svgo,+titleProp,+ref![path]',
},
},
},
],
],
};
 
Function `selectStyleLoaders` has 47 lines of code (exceeds 25 allowed). Consider refactoring.
const selectStyleLoaders = (
state: BuildConfig,
cssLoaderOptions: object,
preProcessor?: string,
) => {
const loaders = [
isEnvDevelopment(state) && require.resolve('style-loader'),
isEnvProduction(state) && {
loader: MiniCssExtractPlugin.loader,
options: shouldUseRelativeAssetPaths(state)
? { publicPath: '../../' }
: {},
},
{
loader: require.resolve('css-loader'),
options: cssLoaderOptions,
},
{
// Options for PostCSS as we reference these options twice
// Adds vendor prefixing based on your specified browser support in
// package.json
loader: require.resolve('postcss-loader'),
options: {
// Necessary for external CSS imports to work
// https://github.com/facebook/create-react-app/issues/2677
ident: 'postcss',
plugins: () => [
require('postcss-flexbugs-fixes'),
require('postcss-preset-env')({
autoprefixer: {
flexbox: 'no-2009',
},
stage: 3,
}),
// Adds PostCSS Normalize as the reset css with default options,
// so that it honors browserslist config in package.json
// which in turn let's users customize the target behavior as per their needs.
postcssNormalize(),
],
sourceMap: isEnvProduction(state) && shouldUseSourceMap(),
},
},
].filter(Boolean) as Loader[];
if (preProcessor) {
loaders.push(
{
loader: require.resolve('resolve-url-loader'),
options: {
sourceMap: isEnvProduction(state) && shouldUseSourceMap(),
},
},
{
loader: require.resolve(preProcessor),
options: {
sourceMap: true,
},
},
);
}
return loaders;
};
 
const selectDefaultRules = (state: BuildConfig) => [
{ parser: { requireEnsure: false } },
{
test: jsRegex,
loader: require.resolve('babel-loader'),
include: selectAppPath(state),
options: {
customize: require.resolve('babel-preset-react-app/webpack-overrides'),
babelrc: false,
configFile: false,
cacheDirectory: true,
cacheCompression: false,
compact: isEnvProduction(state),
...(state.rc?.babel?.modifier?.(defaultBabelConfig) ??
defaultBabelConfig),
},
},
// "postcss" loader applies autoprefixer to our CSS.
// "css" loader resolves paths in CSS and adds assets as dependencies.
// "style" loader turns CSS into JS modules that inject <style> tags.
// In production, we use MiniCSSExtractPlugin to extract that CSS
// to a file, but in development "style" loader enables hot editing
// of CSS.
// By default we support CSS Modules with the extension .module.css
{
test: cssRegex,
exclude: cssModuleRegex,
use: selectStyleLoaders(state, {
importLoaders: 1,
sourceMap: isEnvProduction(state) && shouldUseSourceMap(),
}),
// Don't consider CSS imports dead code even if the
// containing package claims to have no side effects.
// Remove this when webpack adds a warning or an error for this.
// See https://github.com/webpack/webpack/issues/6571
sideEffects: true,
},
// Adds support for CSS Modules (https://github.com/css-modules/css-modules)
// using the extension .module.css
{
test: cssModuleRegex,
use: selectStyleLoaders(state, {
importLoaders: 1,
sourceMap: isEnvProduction(state) && shouldUseSourceMap(),
modules: {
getLocalIdent: getCSSModuleLocalIdent,
},
}),
},
// Opt-in support for SASS (using .scss or .sass extensions).
// By default we support SASS Modules with the
// extensions .module.scss or .module.sass
{
test: sassRegex,
exclude: sassModuleRegex,
use: selectStyleLoaders(
state,
{
importLoaders: 3,
sourceMap: isEnvProduction(state) && shouldUseSourceMap(),
},
require.resolve('sass-loader'),
),
// Don't consider CSS imports dead code even if the
// containing package claims to have no side effects.
// Remove this when webpack adds a warning or an error for this.
// See https://github.com/webpack/webpack/issues/6571
sideEffects: true,
},
// Adds support for CSS Modules, but using SASS
// using the extension .module.scss or .module.sass
{
test: sassModuleRegex,
use: selectStyleLoaders(
state,
{
importLoaders: 3,
sourceMap: isEnvProduction(state) && shouldUseSourceMap(),
modules: {
getLocalIdent: getCSSModuleLocalIdent,
},
},
require.resolve('sass-loader'),
),
},
];
 
const selectEnvRules = (state: BuildConfig) => {
switch (state.env) {
case 'development':
return [
{
test: jsRegex,
loader: require.resolve('eslint-loader'),
include: selectAppPath(state),
enforce: 'pre' as const,
options: {
cache: true,
formatter: require.resolve('react-dev-utils/eslintFormatter'),
eslintPath: require.resolve('eslint'),
baseConfig: {
extends: [require.resolve('eslint-config-brookjs')],
},
useEslintrc: false,
},
},
];
default:
return [];
}
};
 
const selectDefaultPlugins = (state: BuildConfig) => [
// @TODO(mAAdhaTTah) readd–rollup gets sad :(
// This gives some necessary context to module not found errors, such as
// the requesting resource.
// new ModuleNotFoundPlugin(selectAppPath(state)),
// Generate an asset manifest file with the following content:
// - "files" key: Mapping of all asset filenames to their corresponding
// output file so that tools can pick it up without having to parse
// `index.html`
// - "entrypoints" key: Array of files which are included in `index.html`,
// can be used to reconstruct the HTML if necessary
new ManifestPlugin({
fileName: 'asset-manifest.json',
publicPath: selectPublicPath(state),
generate: (seed, files, entrypoints) => ({
files: files.reduce((manifest, file) => {
if (file.name != null) manifest[file.name] = file.path;
return manifest;
}, seed as Record<string, string>),
 
entrypoints: Object.entries(entrypoints).reduce(
(entries, [key, entry]) => ({
...entries,
[key]: entry.filter(fileName => !fileName.endsWith('.map')),
}),
{},
),
}),
}),
// 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$/),
// Generates an `index.html` file with the <script> injected.
new HtmlWebpackPlugin(
Object.assign(
{},
{
inject: true,
template: selectAppHtml(state),
},
isEnvProduction(state)
? {
minify: {
removeComments: true,
collapseWhitespace: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}
: undefined,
),
),
// new InterpolateHtmlPlugin(HtmlWebpackPlugin, {
// // Useful for determining whether we’re running in production mode.
// // Most importantly, it switches React into the correct mode.
// NODE_ENV: process.env.NODE_ENV || 'development',
// // Useful for resolving the correct path to static assets in `public`.
// // For example, <img src={process.env.PUBLIC_URL + '/img/logo.png'} />.
// // This should only be used as an escape hatch. Normally you would put
// // images into the `src` and `import` them in code to get their paths.
// PUBLIC_URL: selectPublicUrl(state)
// })
];
 
Function `selectEnvPlugins` has 40 lines of code (exceeds 25 allowed). Consider refactoring.
const selectEnvPlugins = (state: BuildConfig) => {
const plugins = state.watch
? [
// 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/facebook/create-react-app/issues/186
// @TODO(mAAdhaTTah) readd–rollup gets sad :(
// new WatchMissingNodeModulesPlugin(selectAppNodeModulesPath(state))
]
: [];
switch (state.env) {
case 'development':
return [
...plugins,
state.extension === 'ts' &&
// Only typecheck if we're watching.
state.watch &&
new ForkTsCheckerWebpackPlugin({
async: true,
useTypescriptIncrementalApi: true,
checkSyntacticErrors: true,
tsconfig: path.join(state.cwd, 'tsconfig.json'),
reportFiles: [path.join(state.cwd, state.rc?.dir ?? 'src', '**')],
silent: true,
formatter: require('react-dev-utils/typescriptFormatter'),
}),
new CaseSensitivePathsPlugin({
debug: false,
}),
].filter(Boolean);
case 'production':
return [
...plugins,
new ShakePlugin({
warnings: {
global: false,
module: false,
},
}),
// shouldInlineRuntimeChunk(state) &&
// new InlineChunkHtmlPlugin(HtmlWebpackPlugin, [/runtime-.+[.]js/]),
new MiniCssExtractPlugin({
// Options similar to the same options in webpackOptions.output
// both options are optional
filename: '[name].[contenthash:8].css',
chunkFilename: '[name].[contenthash:8].chunk.css',
}),
];
default:
return plugins;
}
};
 
const selectCmdPlugins = (state: BuildConfig) => {
switch (state.cmd) {
case 'build':
return [];
case 'start':
return [new webpack.HotModuleReplacementPlugin()];
default:
return unreachable(state.cmd);
}
};
 
const selectWebpackEntry = (
state: BuildConfig,
): webpack.Configuration['entry'] => {
let entry = state.rc?.webpack?.entry ?? `index`;
 
if (typeof entry === 'string') {
return path.join(selectAppPath(state), entry);
}
 
if (Array.isArray(entry)) {
return entry.map(e => path.join(selectAppPath(state), e));
}
 
if (typeof entry === 'object') {
for (const [key, value] of Object.entries(entry)) {
entry = {
...entry,
[key]: path.join(selectAppPath(state), value),
};
}
}
 
return entry;
};
 
const selectFilename = (state: BuildConfig): string => {
let filename = state.rc?.webpack?.output?.filename ?? '[name].js';
 
if (typeof filename === 'function') {
filename = filename(state);
 
if (typeof filename !== 'string') {
throw new Error('rc.webpack.filename function should return a string.');
}
}
 
return filename;
};
 
const selectPath = (state: BuildConfig) =>
path.join(state.cwd, state.rc?.webpack?.output?.path ?? 'dist/');
 
const selectOutput = (state: BuildConfig): webpack.Configuration['output'] => ({
path: selectPath(state),
pathinfo: isEnvDevelopment(state),
filename: selectFilename(state),
// TODO: remove this when upgrading to webpack 5
futureEmitAssets: true,
chunkFilename: isEnvProduction(state)
? '[name].[contenthash:8].chunk.js'
: isEnvDevelopment(state)
? '[name].chunk.js'
: undefined,
// Webpack uses `publicPath` to determine where the app is being served from.
// It requires a trailing slash, or the file assets will get an incorrect path.
// We inferred the "public path" (such as / or /my-project) from homepage.
publicPath: selectPublicUrlOrPath(state),
// Prevents conflicts when multiple Webpack runtimes (from different apps)
// are used on the same page.
jsonpFunction: `webpackJsonp${camelcase(state.name, {
pascalCase: true,
})}`,
// this defaults to 'window', but by setting it to 'this' then
// module chunks which are built will work in web workers as well.
globalObject: 'this',
});
 
const selectMinimizer = (state: BuildConfig) => [
// This is only used in production mode
new TerserPlugin({
terserOptions: {
parse: {
// We want terser to parse ecma 8 code. However, we don't want it
// to apply any minification steps that turns valid ecma 5 code
// into invalid ecma 5 code. This is why the 'compress' and 'output'
// sections only apply transformations that are ecma 5 safe
// https://github.com/facebook/create-react-app/pull/4234
ecma: 8,
},
compress: {
ecma: 5,
warnings: false,
// Disabled because of an issue with Uglify breaking seemingly valid code:
// https://github.com/facebook/create-react-app/issues/2376
// Pending further investigation:
// https://github.com/mishoo/UglifyJS2/issues/2011
comparisons: false,
// Disabled because of an issue with Terser breaking valid code:
// https://github.com/facebook/create-react-app/issues/5250
// Pending further investigation:
// https://github.com/terser-js/terser/issues/120
inline: 2,
},
mangle: {
safari10: true,
},
// Added for profiling in devtools
keep_classnames: isEnvProductionProfile(),
keep_fnames: isEnvProductionProfile(),
output: {
ecma: 5,
comments: false,
// Turned on because emoji and regex is not minified properly using default
// https://github.com/facebook/create-react-app/issues/2488
ascii_only: true,
},
},
sourceMap: shouldUseSourceMap(),
}),
// This is only used in production mode
new OptimizeCSSAssetsPlugin({
cssProcessorOptions: {
parser: safePostCssParser,
map: shouldUseSourceMap()
? {
// `inline: false` forces the sourcemap to be output into a
// separate file
inline: false,
// `annotation: true` appends the sourceMappingURL to the end of
// the css file, helping the browser find the sourcemap
annotation: true,
}
: false,
},
cssProcessorPluginOptions: {
preset: ['default', { minifyFontValues: { removeQuotes: false } }],
},
}),
];
 
Function `addHotReload` has a Cognitive Complexity of 12 (exceeds 5 allowed). Consider refactoring.
const addHotReload = (
entry: webpack.Configuration['entry'],
): webpack.Configuration['entry'] => {
const client = require.resolve('react-dev-utils/webpackHotDevClient');
 
if (typeof entry === 'string') {
return [client, entry];
}
 
if (Array.isArray(entry)) {
return [client, ...entry];
}
 
// @TODO(mAAdhaTTah) what to do if function provided?
if (typeof entry === 'function') {
return entry;
}
 
if (typeof entry === 'object') {
for (const key in entry) {
let value = entry[key];
 
if (Array.isArray(value)) {
value = [client, ...value];
}
 
if (typeof value === 'string') {
value = [client, value];
}
 
entry[key] = value;
}
}
 
return entry;
};
 
Function `selectWebpackConfig` has 72 lines of code (exceeds 25 allowed). Consider refactoring.
export const selectWebpackConfig = (
state: BuildConfig,
): webpack.Configuration => {
let entry = selectWebpackEntry(state);
 
if (state.cmd === 'start') {
entry = addHotReload(entry);
}
 
const config: webpack.Configuration = {
entry,
output: selectOutput(state),
bail: isEnvProduction(state),
mode: state.env,
devtool: isEnvProduction(state) ? 'source-map' : 'cheap-module-source-map',
resolve: {
mainFields: ['module', 'main'],
// These are the reasonable defaults supported by the Node ecosystem.
// We also include JSX as a common component filename extension to support
// some tools, although we do not recommend using it, see:
// https://github.com/facebook/create-react-app/issues/290
// `web` extension prefixes have been added for better support
// for React Native Web.
extensions: [
'web.mjs',
'mjs',
'web.js',
'js',
'web.ts',
'ts',
'web.tsx',
'tsx',
'json',
'web.jsx',
'jsx',
]
.map(ext => `.${ext}`)
.filter(ext => state.extension === 'ts' || !ext.includes('ts')),
alias: {
// Support React Native Web
// https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/
'react-native': 'react-native-web',
// Allows for better profiling with ReactDevTools
...(isEnvProductionProfile() && {
'react-dom$': 'react-dom/profiling',
'scheduler/tracing': 'scheduler/tracing-profiling',
}),
...{
// Add additional aliases here.
},
},
plugins: [
// @TODO(mAAdhaTTah) revisit if we want to add these plugins to the build
// Adds support for installing with Plug'n'Play, leading to faster installs and adding
// guards against forgotten dependencies and such.
// PnpWebpackPlugin,
// 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])
],
},
// resolveLoader: {
// plugins: [
// // Also related to Plug'n'Play, but this time it tells Webpack to load its loaders
// // from the current package.
// PnpWebpackPlugin.moduleLoader(module),
// ],
// },
module: {
strictExportPresence: true,
rules: [...selectDefaultRules(state), ...selectEnvRules(state)],
},
plugins: [
...selectDefaultPlugins(state),
...selectEnvPlugins(state),
...selectCmdPlugins(state),
],
optimization: {
minimize: isEnvProduction(state),
minimizer: selectMinimizer(state),
// Automatically split vendor and commons
// https://twitter.com/wSokra/status/969633336732905474
// https://medium.com/webpack/webpack-4-code-splitting-chunk-graph-and-the-splitchunks-optimization-be739a861366
// @TODO(mAAdhaTTah) figure out why this results in no app bootstrapping when running start
// splitChunks: {
// chunks: 'all',
// name: false
// },
// Keep the runtime chunk separated to enable long term caching
// https://twitter.com/wSokra/status/969679223278505985
// https://github.com/facebook/create-react-app/issues/5358
runtimeChunk: {
name: entrypoint => `runtime-${entrypoint.name}`,
},
},
// 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: {
module: 'empty',
dgram: 'empty',
dns: 'mock',
fs: 'empty',
http2: 'empty',
net: 'empty',
tls: 'empty',
child_process: 'empty',
},
};
 
return (
state.rc?.webpack?.modifier?.(config, {
env: state.env,
cmd: state.cmd,
}) ?? config
);
};
 
export const selectServerConfig = (
state: BuildConfig,
): WebpackDevServer.Configuration => ({
// WebpackDevServer 2.4.3 introduced a security fix that prevents remote
// websites from potentially accessing local content through DNS rebinding:
// https://github.com/webpack/webpack-dev-server/issues/887
// https://medium.com/webpack/webpack-dev-server-middleware-security-issues-1489d950874a
// However, it made several existing use cases such as development in cloud
// environment or subdomains in development significantly more complicated:
// https://github.com/facebook/create-react-app/issues/2271
// https://github.com/facebook/create-react-app/issues/2233
// While we're investigating better solutions, for now we will take a
// compromise. Since our WDS configuration only serves files in the `public`
// folder we won't consider accessing them a vulnerability. However, if you
// use the `proxy` feature, it gets more dangerous because it can expose
// remote code execution vulnerabilities in backends like Django and Rails.
// So we will disable the host check normally, but enable it if you have
// specified the `proxy` setting. Finally, we let you override it if you
// really know what you're doing with a special environment variable.
// @TODO(mAAdhaTTah) make this configurable
disableHostCheck: false,
// Enable gzip compression of generated files.
compress: true,
// Silence WebpackDevServer's own logs since they're generally not useful.
// It will still show compile warnings and errors with this setting.
clientLogLevel: 'silent',
// By default WebpackDevServer serves physical files from current directory
// in addition to all the virtual build products that it serves from memory.
// This is confusing because those files won’t automatically be available in
// production build folder unless we copy them. However, copying the whole
// project directory is dangerous because we may expose sensitive files.
// Instead, we establish a convention that only files in `public` directory
// get served. Our build script will copy `public` into the `build` folder.
// In `index.html`, you can get URL of `public` folder with %PUBLIC_URL%:
// <link rel="icon" href="%PUBLIC_URL%/favicon.ico">
// In JavaScript code, you can access it with `process.env.PUBLIC_URL`.
// Note that we only recommend to use `public` folder as an escape hatch
// for files like `favicon.ico`, `manifest.json`, and libraries that are
// 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: path.join(state.cwd, 'public'),
 
// By default files from `contentBase` will not trigger a page reload.
watchContentBase: true,
// Enable hot reloading server. It will provide WDS_SOCKET_PATH endpoint
// for the WebpackDevServer client so it can learn when the files were
// updated. The WebpackDevServer client is included as an entry point
// in the Webpack development configuration. Note that only changes
// to CSS are currently hot reloaded. JS changes will refresh the browser.
hot: true,
// Use 'ws' instead of 'sockjs-node' on server since we're using native
// websockets in `webpackHotDevClient`.
transportMode: 'ws',
// Prevent a WS client from getting injected as we're already including
// `webpackHotDevClient`.
injectClient: false,
// Enable custom sockjs pathname for websocket connection to hot reloading server.
// Enable custom sockjs hostname, pathname and port for websocket connection
// to hot reloading server.
 
// @TODO(mAAdhaTTah) make these 3 configurable
// sockHost,
// sockPath,
// sockPort,
 
// 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: selectPublicPath(),
// 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,
// Reportedly, this avoids CPU overload on some systems.
// https://github.com/facebook/create-react-app/issues/293
// src/node_modules is not ignored to support absolute imports
// https://github.com/facebook/create-react-app/issues/1065
watchOptions: {
ignored: ignoredFiles(selectAppPath(state)),
},
// https: selectHttpsConfig(state),
// host: selectHost(state),
overlay: false,
historyApiFallback: {
// Paths with dots should still use the history fallback.
// See https://github.com/facebook/create-react-app/issues/387.
disableDotRule: true,
index: selectPublicUrlOrPath(state),
},
// public: selectAllowHosts(state),
// `proxy` is run between `before` and `after` `webpack-dev-server` hooks
// proxy: selectProxy(state),
before(app, server) {
// 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());
},
after(app) {
// Redirect to `PUBLIC_URL` or `homepage` from `package.json` if url not match
// app.use(redirectServedPath(selectPublicUrlOrPath(state)));
 
// 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());
},
});