|
|
@ -6,14 +6,12 @@ const FaviconsWebpackPlugin = require("favicons-webpack-plugin"); |
|
|
|
const CaseSensitivePathsPlugin = require("case-sensitive-paths-webpack-plugin"); |
|
|
|
const CaseSensitivePathsPlugin = require("case-sensitive-paths-webpack-plugin"); |
|
|
|
const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); |
|
|
|
const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); |
|
|
|
const DashboardPlugin = require("webpack-dashboard/plugin"); |
|
|
|
const DashboardPlugin = require("webpack-dashboard/plugin"); |
|
|
|
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin; |
|
|
|
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer") |
|
|
|
|
|
|
|
.BundleAnalyzerPlugin; |
|
|
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); |
|
|
|
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); |
|
|
|
const HappyPack = require("happypack"); |
|
|
|
|
|
|
|
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); |
|
|
|
const ForkTsCheckerWebpackPlugin = require("fork-ts-checker-webpack-plugin"); |
|
|
|
|
|
|
|
|
|
|
|
const { |
|
|
|
const { getClientEnvironment } = require("./env"); |
|
|
|
getClientEnvironment |
|
|
|
|
|
|
|
} = require("./env"); |
|
|
|
|
|
|
|
const paths = require("../paths"); |
|
|
|
const paths = require("../paths"); |
|
|
|
|
|
|
|
|
|
|
|
// Webpack uses `publicPath` to determine where the app is being served from.
|
|
|
|
// Webpack uses `publicPath` to determine where the app is being served from.
|
|
|
@ -24,7 +22,7 @@ const publicPath = paths.publicPath; |
|
|
|
// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
|
|
|
|
// Omit trailing slash as %PUBLIC_URL%/xyz looks better than %PUBLIC_URL%xyz.
|
|
|
|
const publicUrl = paths.publicUrl.slice(0, -1); |
|
|
|
const publicUrl = paths.publicUrl.slice(0, -1); |
|
|
|
// Source maps are resource heavy and can cause out of memory issue for large source files.
|
|
|
|
// Source maps are resource heavy and can cause out of memory issue for large source files.
|
|
|
|
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false'; |
|
|
|
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== "false"; |
|
|
|
// Get environment variables to inject into our app.
|
|
|
|
// Get environment variables to inject into our app.
|
|
|
|
const environ = getClientEnvironment(publicUrl); |
|
|
|
const environ = getClientEnvironment(publicUrl); |
|
|
|
|
|
|
|
|
|
|
@ -37,27 +35,29 @@ const postCssConfig = { |
|
|
|
plugins: () => [ |
|
|
|
plugins: () => [ |
|
|
|
require("postcss-flexbugs-fixes"), |
|
|
|
require("postcss-flexbugs-fixes"), |
|
|
|
require("postcss-preset-env")({ |
|
|
|
require("postcss-preset-env")({ |
|
|
|
stage: 0, |
|
|
|
stage: 0 |
|
|
|
}), |
|
|
|
}) |
|
|
|
], |
|
|
|
] |
|
|
|
}, |
|
|
|
} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const sassConfig = { |
|
|
|
const sassConfig = { |
|
|
|
loader: require.resolve("sass-loader"), |
|
|
|
loader: require.resolve("sass-loader"), |
|
|
|
options: {}, |
|
|
|
options: {} |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const rules = (env) => { |
|
|
|
const rules = env => { |
|
|
|
// "postcss" loader applies autoprefixer to our CSS.
|
|
|
|
// "postcss" loader applies autoprefixer to our CSS.
|
|
|
|
// "css" loader resolves paths in CSS and adds assets as dependencies.
|
|
|
|
// "css" loader resolves paths in CSS and adds assets as dependencies.
|
|
|
|
// "style" loader turns CSS into JS modules that inject <style> tags.
|
|
|
|
// "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 production, we use a plugin to extract that CSS to a file, but
|
|
|
|
// in development "style" loader enables hot editing of CSS.
|
|
|
|
// in development "style" loader enables hot editing of CSS.
|
|
|
|
const styleLoader = |
|
|
|
const styleLoader = |
|
|
|
(env === "prod") ? { |
|
|
|
env === "prod" |
|
|
|
|
|
|
|
? { |
|
|
|
loader: MiniCssExtractPlugin.loader |
|
|
|
loader: MiniCssExtractPlugin.loader |
|
|
|
} : require.resolve("style-loader"); |
|
|
|
} |
|
|
|
|
|
|
|
: require.resolve("style-loader"); |
|
|
|
const cssRule = { |
|
|
|
const cssRule = { |
|
|
|
test: /\.css$/, |
|
|
|
test: /\.css$/, |
|
|
|
use: [ |
|
|
|
use: [ |
|
|
@ -65,10 +65,10 @@ const rules = (env) => { |
|
|
|
{ |
|
|
|
{ |
|
|
|
loader: require.resolve("css-loader"), |
|
|
|
loader: require.resolve("css-loader"), |
|
|
|
options: { |
|
|
|
options: { |
|
|
|
importLoaders: 1, |
|
|
|
importLoaders: 1 |
|
|
|
}, |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
postCssConfig, |
|
|
|
postCssConfig |
|
|
|
] |
|
|
|
] |
|
|
|
}; |
|
|
|
}; |
|
|
|
const sassRule = { |
|
|
|
const sassRule = { |
|
|
@ -78,14 +78,15 @@ const rules = (env) => { |
|
|
|
{ |
|
|
|
{ |
|
|
|
loader: require.resolve("css-loader"), |
|
|
|
loader: require.resolve("css-loader"), |
|
|
|
options: { |
|
|
|
options: { |
|
|
|
importLoaders: 1, |
|
|
|
importLoaders: 1 |
|
|
|
}, |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
postCssConfig, |
|
|
|
postCssConfig, |
|
|
|
sassConfig, |
|
|
|
sassConfig |
|
|
|
], |
|
|
|
] |
|
|
|
}; |
|
|
|
}; |
|
|
|
return [{ |
|
|
|
return [ |
|
|
|
|
|
|
|
{ |
|
|
|
// "oneOf" will traverse all following loaders until one will
|
|
|
|
// "oneOf" will traverse all following loaders until one will
|
|
|
|
// match the requirements. when no loader matches it will fall
|
|
|
|
// match the requirements. when no loader matches it will fall
|
|
|
|
// back to the "file" loader at the end of the loader list.
|
|
|
|
// back to the "file" loader at the end of the loader list.
|
|
|
@ -97,17 +98,32 @@ const rules = (env) => { |
|
|
|
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/], |
|
|
|
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/], |
|
|
|
loader: require.resolve("url-loader"), |
|
|
|
loader: require.resolve("url-loader"), |
|
|
|
options: { |
|
|
|
options: { |
|
|
|
limit: (env === "prod") ? 10000 : 0, |
|
|
|
limit: env === "prod" ? 10000 : 0, |
|
|
|
name: "static/media/[name].[hash:8].[ext]", |
|
|
|
name: "static/media/[name].[hash:8].[ext]" |
|
|
|
}, |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
cssRule, |
|
|
|
cssRule, |
|
|
|
sassRule, |
|
|
|
sassRule, |
|
|
|
// Process TypeScript with TSC through HappyPack.
|
|
|
|
// Process TypeScript with TSC through HappyPack.
|
|
|
|
{ |
|
|
|
{ |
|
|
|
test: /\.tsx?$/, |
|
|
|
test: /\.tsx?$/, |
|
|
|
use: "happypack/loader?id=ts", |
|
|
|
|
|
|
|
include: [paths.clientDir, paths.commonDir], |
|
|
|
include: [paths.clientDir, paths.commonDir], |
|
|
|
|
|
|
|
use: [ |
|
|
|
|
|
|
|
{ loader: "cache-loader" }, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
loader: "thread-loader", |
|
|
|
|
|
|
|
options: { |
|
|
|
|
|
|
|
workers: require("os").cpus().length - 1 |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
loader: "ts-loader", |
|
|
|
|
|
|
|
options: { |
|
|
|
|
|
|
|
configFile: paths.clientTsConfig, |
|
|
|
|
|
|
|
happyPackMode: true |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
] |
|
|
|
}, |
|
|
|
}, |
|
|
|
// "file" loader makes sure those assets get served by WebpackDevServer.
|
|
|
|
// "file" loader makes sure those assets get served by WebpackDevServer.
|
|
|
|
// When you `import` an asset, you get its (virtual) filename.
|
|
|
|
// When you `import` an asset, you get its (virtual) filename.
|
|
|
@ -122,20 +138,23 @@ const rules = (env) => { |
|
|
|
exclude: [/\.js$/, /\.html$/, /\.json$/], |
|
|
|
exclude: [/\.js$/, /\.html$/, /\.json$/], |
|
|
|
loader: require.resolve("file-loader"), |
|
|
|
loader: require.resolve("file-loader"), |
|
|
|
options: { |
|
|
|
options: { |
|
|
|
name: "static/media/[name].[hash:8].[ext]", |
|
|
|
name: "static/media/[name].[hash:8].[ext]" |
|
|
|
}, |
|
|
|
} |
|
|
|
}, |
|
|
|
} |
|
|
|
], |
|
|
|
] |
|
|
|
}, ]; |
|
|
|
} |
|
|
|
} |
|
|
|
]; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
const getConfig = module.exports = (env) => { |
|
|
|
const getConfig = (module.exports = env => { |
|
|
|
const isProd = (env === "prod"); |
|
|
|
const isProd = env === "prod"; |
|
|
|
const isDev = (env === "dev"); |
|
|
|
const isDev = env === "dev"; |
|
|
|
// Assert this just to be safe.
|
|
|
|
// Assert this just to be safe.
|
|
|
|
// Development builds of React are slow and not intended for production.
|
|
|
|
// Development builds of React are slow and not intended for production.
|
|
|
|
if (isProd && environ.stringified["process.env"].NODE_ENV !== '"production"') { |
|
|
|
if ( |
|
|
|
|
|
|
|
isProd && |
|
|
|
|
|
|
|
environ.stringified["process.env"].NODE_ENV !== '"production"' |
|
|
|
|
|
|
|
) { |
|
|
|
throw new Error("Production builds must have NODE_ENV=production."); |
|
|
|
throw new Error("Production builds must have NODE_ENV=production."); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
@ -143,7 +162,8 @@ const getConfig = module.exports = (env) => { |
|
|
|
new HtmlWebpackPlugin({ |
|
|
|
new HtmlWebpackPlugin({ |
|
|
|
inject: true, |
|
|
|
inject: true, |
|
|
|
template: paths.clientHtml, |
|
|
|
template: paths.clientHtml, |
|
|
|
minify: isProd ? { |
|
|
|
minify: isProd |
|
|
|
|
|
|
|
? { |
|
|
|
removeComments: true, |
|
|
|
removeComments: true, |
|
|
|
collapseWhitespace: true, |
|
|
|
collapseWhitespace: true, |
|
|
|
removeRedundantAttributes: true, |
|
|
|
removeRedundantAttributes: true, |
|
|
@ -153,96 +173,99 @@ const getConfig = module.exports = (env) => { |
|
|
|
keepClosingSlash: true, |
|
|
|
keepClosingSlash: true, |
|
|
|
minifyJS: true, |
|
|
|
minifyJS: true, |
|
|
|
minifyCSS: true, |
|
|
|
minifyCSS: true, |
|
|
|
minifyURLs: true, |
|
|
|
minifyURLs: true |
|
|
|
} : undefined, |
|
|
|
} |
|
|
|
|
|
|
|
: undefined |
|
|
|
}), |
|
|
|
}), |
|
|
|
new FaviconsWebpackPlugin(path.resolve(paths.clientDir, "images", "favicon-96x96.png")), |
|
|
|
new FaviconsWebpackPlugin( |
|
|
|
|
|
|
|
path.resolve(paths.clientDir, "images", "favicon-96x96.png") |
|
|
|
|
|
|
|
), |
|
|
|
// Makes some environment variables available to the JS code, for example:
|
|
|
|
// Makes some environment variables available to the JS code, for example:
|
|
|
|
// if (process.env.NODE_ENV === "production") { ... }. See `./env.js`.
|
|
|
|
// if (process.env.NODE_ENV === "production") { ... }. See `./env.js`.
|
|
|
|
// It is absolutely essential that NODE_ENV was set to production here.
|
|
|
|
// It is absolutely essential that NODE_ENV was set to production here.
|
|
|
|
// Otherwise React will be compiled in the very slow development mode.
|
|
|
|
// Otherwise React will be compiled in the very slow development mode.
|
|
|
|
new webpack.DefinePlugin(environ.stringified), |
|
|
|
new webpack.DefinePlugin(environ.stringified), |
|
|
|
new CaseSensitivePathsPlugin(), |
|
|
|
new CaseSensitivePathsPlugin(), |
|
|
|
isProd && new UglifyJsPlugin({ |
|
|
|
isProd && |
|
|
|
sourceMap: shouldUseSourceMap, |
|
|
|
new UglifyJsPlugin({ |
|
|
|
|
|
|
|
sourceMap: shouldUseSourceMap |
|
|
|
}), |
|
|
|
}), |
|
|
|
isDev && new webpack.HotModuleReplacementPlugin(), |
|
|
|
isDev && new webpack.HotModuleReplacementPlugin(), |
|
|
|
new webpack.NamedModulesPlugin(), |
|
|
|
new webpack.NamedModulesPlugin(), |
|
|
|
new HappyPack({ |
|
|
|
|
|
|
|
id: "ts", |
|
|
|
|
|
|
|
threads: 2, |
|
|
|
|
|
|
|
loaders: [{ |
|
|
|
|
|
|
|
loader: "ts-loader", |
|
|
|
|
|
|
|
options: { |
|
|
|
|
|
|
|
configFile: paths.clientTsConfig, |
|
|
|
|
|
|
|
happyPackMode: true, |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
}], |
|
|
|
|
|
|
|
}), |
|
|
|
|
|
|
|
new ForkTsCheckerWebpackPlugin({ |
|
|
|
new ForkTsCheckerWebpackPlugin({ |
|
|
|
checkSyntacticErrors: true, |
|
|
|
checkSyntacticErrors: true, |
|
|
|
tsconfig: paths.clientTsConfig, |
|
|
|
tsconfig: paths.clientTsConfig, |
|
|
|
tslint: paths.resolveRoot("tslint.json"), |
|
|
|
tslint: paths.tslintConfig |
|
|
|
}), |
|
|
|
}), |
|
|
|
isDev && new DashboardPlugin(), |
|
|
|
isDev && new DashboardPlugin(), |
|
|
|
new BundleAnalyzerPlugin({ |
|
|
|
new BundleAnalyzerPlugin({ |
|
|
|
analyzerMode: "static", |
|
|
|
analyzerMode: "static", |
|
|
|
openAnalyzer: false, |
|
|
|
openAnalyzer: false, |
|
|
|
reportFilename: path.resolve(paths.serverBuildDir, "report.html"), |
|
|
|
reportFilename: path.resolve(paths.serverBuildDir, "report.html") |
|
|
|
}), |
|
|
|
}), |
|
|
|
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), |
|
|
|
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), |
|
|
|
isProd && new MiniCssExtractPlugin({ |
|
|
|
isProd && |
|
|
|
|
|
|
|
new MiniCssExtractPlugin({ |
|
|
|
filename: "static/css/[name].[chunkhash:8].css", |
|
|
|
filename: "static/css/[name].[chunkhash:8].css", |
|
|
|
chunkFilename: "static/css/[id].[chunkhash:8].css", |
|
|
|
chunkFilename: "static/css/[id].[chunkhash:8].css" |
|
|
|
}) |
|
|
|
}) |
|
|
|
].filter(Boolean); |
|
|
|
].filter(Boolean); |
|
|
|
|
|
|
|
|
|
|
|
return { |
|
|
|
return { |
|
|
|
mode: isProd ? "production" : "development", |
|
|
|
mode: isProd ? "production" : "development", |
|
|
|
bail: isProd, |
|
|
|
bail: isProd, |
|
|
|
devtool: shouldUseSourceMap ? |
|
|
|
devtool: shouldUseSourceMap |
|
|
|
isProd ? "source-map" : "inline-source-map" : false, |
|
|
|
? isProd |
|
|
|
|
|
|
|
? "source-map" |
|
|
|
|
|
|
|
: "inline-source-map" |
|
|
|
|
|
|
|
: false, |
|
|
|
entry: [ |
|
|
|
entry: [ |
|
|
|
isDev && require.resolve("react-hot-loader/patch"), |
|
|
|
isDev && require.resolve("react-hot-loader/patch"), |
|
|
|
isDev && require.resolve("react-dev-utils/webpackHotDevClient"), |
|
|
|
isDev && require.resolve("react-dev-utils/webpackHotDevClient"), |
|
|
|
require.resolve("./polyfills"), |
|
|
|
require.resolve("./polyfills"), |
|
|
|
paths.clientEntry, |
|
|
|
paths.clientEntry |
|
|
|
].filter(Boolean), |
|
|
|
].filter(Boolean), |
|
|
|
output: { |
|
|
|
output: { |
|
|
|
path: paths.clientBuildDir, |
|
|
|
path: paths.clientBuildDir, |
|
|
|
pathinfo: isDev, |
|
|
|
pathinfo: isDev, |
|
|
|
filename: isProd ? |
|
|
|
filename: isProd |
|
|
|
'static/js/[name].[chunkhash:8].js' : "static/js/bundle.js", |
|
|
|
? "static/js/[name].[chunkhash:8].js" |
|
|
|
chunkFilename: isProd ? |
|
|
|
: "static/js/bundle.js", |
|
|
|
'static/js/[name].[chunkhash:8].chunk.js' : "static/js/[name].chunk.js", |
|
|
|
chunkFilename: isProd |
|
|
|
|
|
|
|
? "static/js/[name].[chunkhash:8].chunk.js" |
|
|
|
|
|
|
|
: "static/js/[name].chunk.js", |
|
|
|
publicPath: publicPath, |
|
|
|
publicPath: publicPath, |
|
|
|
devtoolModuleFilenameTemplate: isDev ? |
|
|
|
devtoolModuleFilenameTemplate: isDev |
|
|
|
(info) => |
|
|
|
? info => |
|
|
|
"webpack://" + path.resolve(info.absoluteResourcePath).replace(/\\/g, "/") : undefined, |
|
|
|
"webpack://" + |
|
|
|
|
|
|
|
path.resolve(info.absoluteResourcePath).replace(/\\/g, "/") |
|
|
|
|
|
|
|
: undefined |
|
|
|
}, |
|
|
|
}, |
|
|
|
resolve: { |
|
|
|
resolve: { |
|
|
|
extensions: [".ts", ".tsx", ".js", ".json", ".scss"], |
|
|
|
extensions: [".ts", ".tsx", ".js", ".json", ".scss"], |
|
|
|
alias: { |
|
|
|
alias: { |
|
|
|
"@client": paths.clientDir, |
|
|
|
"@client": paths.clientDir, |
|
|
|
"@common": paths.commonDir, |
|
|
|
"@common": paths.commonDir |
|
|
|
} |
|
|
|
} |
|
|
|
}, |
|
|
|
}, |
|
|
|
module: { |
|
|
|
module: { |
|
|
|
rules: rules(env), |
|
|
|
rules: rules(env) |
|
|
|
}, |
|
|
|
}, |
|
|
|
plugins: plugins, |
|
|
|
plugins: plugins, |
|
|
|
optimization: { |
|
|
|
optimization: { |
|
|
|
namedModules: isProd, |
|
|
|
namedModules: isProd |
|
|
|
}, |
|
|
|
}, |
|
|
|
devServer: { |
|
|
|
devServer: { |
|
|
|
hot: true, |
|
|
|
hot: true, |
|
|
|
historyApiFallback: true, |
|
|
|
historyApiFallback: true, |
|
|
|
host: "0.0.0.0", |
|
|
|
host: "0.0.0.0", |
|
|
|
port: 8081, |
|
|
|
port: 8081, |
|
|
|
proxy: [{ |
|
|
|
proxy: [ |
|
|
|
|
|
|
|
{ |
|
|
|
context: ["/api"], |
|
|
|
context: ["/api"], |
|
|
|
target: paths.publicUrl, |
|
|
|
target: paths.publicUrl |
|
|
|
}], |
|
|
|
|
|
|
|
}, |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
}; |
|
|
|
] |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
}); |
|
|
|