You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
235 lines
9.5 KiB
235 lines
9.5 KiB
7 years ago
|
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 CaseSensitivePathsPlugin = require("case-sensitive-paths-webpack-plugin");
|
||
|
const WatchMissingNodeModulesPlugin = require("react-dev-utils/WatchMissingNodeModulesPlugin");
|
||
|
const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
|
||
|
|
||
|
const { getClientEnvironment } = require("../env");
|
||
|
const paths = require("../paths");
|
||
|
|
||
|
// 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.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_URL%/xyz looks better than %PUBLIC_URL%xyz.
|
||
|
const publicUrl = paths.publicUrl.slice(0, -1);
|
||
|
// Source maps are resource heavy and can cause out of memory issue for large source files.
|
||
|
const shouldUseSourceMap = process.env.GENERATE_SOURCEMAP !== 'false';
|
||
|
// 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 === "./";
|
||
|
// Get environment variables to inject into our app.
|
||
|
const environ = getClientEnvironment(publicUrl);
|
||
|
|
||
|
// Note: defined here because it will be used more than once.
|
||
|
const cssFilename = "static/css/[name].[contenthash:8].css";
|
||
|
|
||
|
const postCssConfig = {
|
||
|
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",
|
||
|
}),
|
||
|
],
|
||
|
},
|
||
|
};
|
||
|
|
||
|
const rules = (env) => {
|
||
|
// "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.
|
||
|
const cssRule = (env === "dev") ?
|
||
|
{
|
||
|
test: /\.css$/,
|
||
|
use: [
|
||
|
require.resolve("style-loader"),
|
||
|
{
|
||
|
loader: require.resolve("css-loader"),
|
||
|
options: {
|
||
|
importLoaders: 1,
|
||
|
},
|
||
|
},
|
||
|
postCssConfig,
|
||
|
],
|
||
|
} :
|
||
|
{
|
||
|
test: /\.css$/,
|
||
|
loader: ExtractTextPlugin.extract({
|
||
|
fallback: require.resolve('style-loader'),
|
||
|
use: [
|
||
|
{
|
||
|
loader: require.resolve('css-loader'),
|
||
|
options: {
|
||
|
importLoaders: 1,
|
||
|
minimize: true,
|
||
|
sourceMap: shouldUseSourceMap,
|
||
|
},
|
||
|
},
|
||
|
postCssConfig
|
||
|
],
|
||
|
// 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.
|
||
|
publicPath: shouldUseRelativeAssetPaths ?
|
||
|
Array(cssFilename.split("/").length).join("../") :
|
||
|
publicPath,
|
||
|
})
|
||
|
};
|
||
|
return [
|
||
|
{
|
||
|
test: /\.tsx?$/,
|
||
|
enforce: "pre",
|
||
|
loader: require.resolve("tslint-loader"),
|
||
|
options: { typecheck: true, tsConfigFile: paths.appTsConfig },
|
||
|
},
|
||
|
{
|
||
|
// "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]",
|
||
|
},
|
||
|
},
|
||
|
cssRule,
|
||
|
// Process TypeScript with TSC.
|
||
|
{
|
||
|
test: /\.tsx?$/, use: {
|
||
|
loader: "awesome-typescript-loader",
|
||
|
options: { configFileName: paths.appTsConfig }
|
||
|
},
|
||
|
},
|
||
|
// "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
|
||
|
// 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$/, /\.html$/, /\.json$/],
|
||
|
loader: require.resolve("file-loader"),
|
||
|
options: {
|
||
|
name: "static/media/[name].[hash:8].[ext]",
|
||
|
},
|
||
|
},
|
||
|
],
|
||
|
},
|
||
|
];
|
||
|
}
|
||
|
|
||
|
|
||
|
const getConfig = module.exports = (env) => {
|
||
|
const isProd = (env === "prod");
|
||
|
const isDev = (env === "dev");
|
||
|
// Assert this just to be safe.
|
||
|
// Development builds of React are slow and not intended for production.
|
||
|
if (isProd && environ.stringified["process.env"].NODE_ENV !== '"production"') {
|
||
|
throw new Error("Production builds must have NODE_ENV=production.");
|
||
|
}
|
||
|
|
||
|
const plugins = [
|
||
|
new HtmlWebpackPlugin({
|
||
|
inject: true,
|
||
|
template: paths.appHtml,
|
||
|
minify: isProd ? {
|
||
|
removeComments: true,
|
||
|
collapseWhitespace: true,
|
||
|
removeRedundantAttributes: true,
|
||
|
useShortDoctype: true,
|
||
|
removeEmptyAttributes: true,
|
||
|
removeStyleLinkTypeAttributes: true,
|
||
|
keepClosingSlash: true,
|
||
|
minifyJS: true,
|
||
|
minifyCSS: true,
|
||
|
minifyURLs: true,
|
||
|
} : undefined,
|
||
|
}),
|
||
|
// 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(environ.stringified),
|
||
|
new CaseSensitivePathsPlugin(),
|
||
|
// Note: this won"t work without ExtractTextPlugin.extract(..) in `loaders`.
|
||
|
isProd && new ExtractTextPlugin({
|
||
|
filename: cssFilename,
|
||
|
}),
|
||
|
isProd && new UglifyJsPlugin({
|
||
|
sourceMap: shouldUseSourceMap,
|
||
|
}),
|
||
|
isDev && new webpack.NamedModulesPlugin(),
|
||
|
isDev && new webpack.HotModuleReplacementPlugin(),
|
||
|
isDev && new WatchMissingNodeModulesPlugin(paths.nodeModulesDir),
|
||
|
].filter(Boolean);
|
||
|
|
||
|
return {
|
||
|
bail: isProd,
|
||
|
devtool: shouldUseSourceMap ?
|
||
|
isProd ? "source-map" : "eval-source-map" :
|
||
|
false,
|
||
|
entry: [
|
||
|
isDev && require.resolve("react-hot-loader/patch"),
|
||
|
isDev && require.resolve("react-dev-utils/webpackHotDevClient"),
|
||
|
require.resolve("./polyfills"),
|
||
|
paths.appEntry,
|
||
|
].filter(Boolean),
|
||
|
output: {
|
||
|
path: paths.appBuildDir,
|
||
|
pathinfo: isDev,
|
||
|
filename: isProd ?
|
||
|
'static/js/[name].[chunkhash:8].js' :
|
||
|
"static/js/bundle.js",
|
||
|
chunkFilename: isProd ?
|
||
|
'static/js/[name].[chunkhash:8].chunk.js' :
|
||
|
"static/js/[name].chunk.js",
|
||
|
publicPath: publicPath,
|
||
|
devtoolModuleFilenameTemplate: isDev ?
|
||
|
(info) =>
|
||
|
"webpack://" + path.resolve(info.absoluteResourcePath).replace(/\\/g, "/") : undefined,
|
||
|
},
|
||
|
resolve: {
|
||
|
extensions: [".ts", ".tsx", ".js", ".json"],
|
||
|
alias: {
|
||
|
"@app": paths.appDir,
|
||
|
"@common": paths.commonDir,
|
||
|
}
|
||
|
},
|
||
|
module: {
|
||
|
rules: rules(env),
|
||
|
},
|
||
|
plugins: plugins,
|
||
|
devServer: {
|
||
|
hot: true,
|
||
|
},
|
||
|
}
|
||
|
};
|