Browse Source

Use cache-loader and thread-loader instead of HappyPack

update-deps
Alex Mikhalev 6 years ago
parent
commit
69c4c1c8e1
  1. 2
      .gitignore
  2. 445
      client/webpack.config.js
  3. 37
      package.json
  4. 1
      paths.js
  5. 629
      yarn.lock

2
.gitignore vendored

@ -1,6 +1,8 @@
/node_modules /node_modules
package-lock.json package-lock.json
npm-debug* npm-debug*
yarn-error*
/.cache-loader
/dist /dist
/public /public
.idea .idea

445
client/webpack.config.js

@ -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,225 +22,250 @@ 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);
const postCssConfig = { const postCssConfig = {
loader: require.resolve("postcss-loader"), loader: require.resolve("postcss-loader"),
options: { options: {
// Necessary for external CSS imports to work // Necessary for external CSS imports to work
// https://github.com/facebookincubator/create-react-app/issues/2677 // https://github.com/facebookincubator/create-react-app/issues/2677
ident: "postcss", ident: "postcss",
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 ? {
} : require.resolve("style-loader"); loader: MiniCssExtractPlugin.loader
const cssRule = { }
test: /\.css$/, : require.resolve("style-loader");
use: [ const cssRule = {
styleLoader, test: /\.css$/,
{ use: [
loader: require.resolve("css-loader"), styleLoader,
options: { {
importLoaders: 1, loader: require.resolve("css-loader"),
}, options: {
}, importLoaders: 1
postCssConfig, }
] },
}; postCssConfig
const sassRule = { ]
test: /\.scss$/, };
use: [ const sassRule = {
styleLoader, test: /\.scss$/,
{ use: [
loader: require.resolve("css-loader"), styleLoader,
options: { {
importLoaders: 1, loader: require.resolve("css-loader"),
}, options: {
}, importLoaders: 1
postCssConfig, }
sassConfig, },
], postCssConfig,
}; sassConfig
return [{ ]
// "oneOf" will traverse all following loaders until one will };
// match the requirements. when no loader matches it will fall return [
// back to the "file" loader at the end of the loader list. {
oneOf: [ // "oneOf" will traverse all following loaders until one will
// "url" loader works like "file" loader except that it embeds assets // match the requirements. when no loader matches it will fall
// smaller than specified limit in bytes as data urls to avoid requests. // back to the "file" loader at the end of the loader list.
// a missing `test` is equivalent to a match. oneOf: [
{ // "url" loader works like "file" loader except that it embeds assets
test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/], // smaller than specified limit in bytes as data urls to avoid requests.
loader: require.resolve("url-loader"), // a missing `test` is equivalent to a match.
options: { {
limit: (env === "prod") ? 10000 : 0, test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/],
name: "static/media/[name].[hash:8].[ext]", loader: require.resolve("url-loader"),
}, options: {
}, limit: env === "prod" ? 10000 : 0,
cssRule, name: "static/media/[name].[hash:8].[ext]"
sassRule, }
// Process TypeScript with TSC through HappyPack. },
cssRule,
sassRule,
// Process TypeScript with TSC through HappyPack.
{
test: /\.tsx?$/,
include: [paths.clientDir, paths.commonDir],
use: [
{ loader: "cache-loader" },
{ {
test: /\.tsx?$/, loader: "thread-loader",
use: "happypack/loader?id=ts", options: {
include: [paths.clientDir, paths.commonDir], workers: require("os").cpus().length - 1
}
}, },
// "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 loader: "ts-loader",
// it"s runtime that would otherwise processed through "file" loader. options: {
// Also exclude `html` and `json` extensions so they get processed configFile: paths.clientTsConfig,
// by webpacks internal loaders. happyPackMode: true
exclude: [/\.js$/, /\.html$/, /\.json$/], }
loader: require.resolve("file-loader"), }
options: { ]
name: "static/media/[name].[hash:8].[ext]", },
}, // "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
const getConfig = module.exports = (env) => { // it"s runtime that would otherwise processed through "file" loader.
const isProd = (env === "prod"); // Also exclude `html` and `json` extensions so they get processed
const isDev = (env === "dev"); // by webpacks internal loaders.
// Assert this just to be safe. exclude: [/\.js$/, /\.html$/, /\.json$/],
// Development builds of React are slow and not intended for production. loader: require.resolve("file-loader"),
if (isProd && environ.stringified["process.env"].NODE_ENV !== '"production"') { options: {
throw new Error("Production builds must have NODE_ENV=production."); name: "static/media/[name].[hash:8].[ext]"
}
}
]
} }
];
};
const plugins = [ const getConfig = (module.exports = env => {
new HtmlWebpackPlugin({ const isProd = env === "prod";
inject: true, const isDev = env === "dev";
template: paths.clientHtml, // Assert this just to be safe.
minify: isProd ? { // Development builds of React are slow and not intended for production.
removeComments: true, if (
collapseWhitespace: true, isProd &&
removeRedundantAttributes: true, environ.stringified["process.env"].NODE_ENV !== '"production"'
useShortDoctype: true, ) {
removeEmptyAttributes: true, throw new Error("Production builds must have NODE_ENV=production.");
removeStyleLinkTypeAttributes: true, }
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
} : undefined,
}),
new FaviconsWebpackPlugin(path.resolve(paths.clientDir, "images", "favicon-96x96.png")),
// 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(),
isProd && new UglifyJsPlugin({
sourceMap: shouldUseSourceMap,
}),
isDev && new webpack.HotModuleReplacementPlugin(),
new webpack.NamedModulesPlugin(),
new HappyPack({
id: "ts",
threads: 2,
loaders: [{
loader: "ts-loader",
options: {
configFile: paths.clientTsConfig,
happyPackMode: true,
},
}],
}),
new ForkTsCheckerWebpackPlugin({
checkSyntacticErrors: true,
tsconfig: paths.clientTsConfig,
tslint: paths.resolveRoot("tslint.json"),
}),
isDev && new DashboardPlugin(),
new BundleAnalyzerPlugin({
analyzerMode: "static",
openAnalyzer: false,
reportFilename: path.resolve(paths.serverBuildDir, "report.html"),
}),
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
isProd && new MiniCssExtractPlugin({
filename: "static/css/[name].[chunkhash:8].css",
chunkFilename: "static/css/[id].[chunkhash:8].css",
})
].filter(Boolean);
return { const plugins = [
mode: isProd ? "production" : "development", new HtmlWebpackPlugin({
bail: isProd, inject: true,
devtool: shouldUseSourceMap ? template: paths.clientHtml,
isProd ? "source-map" : "inline-source-map" : false, minify: isProd
entry: [ ? {
isDev && require.resolve("react-hot-loader/patch"), removeComments: true,
isDev && require.resolve("react-dev-utils/webpackHotDevClient"), collapseWhitespace: true,
require.resolve("./polyfills"), removeRedundantAttributes: true,
paths.clientEntry, useShortDoctype: true,
].filter(Boolean), removeEmptyAttributes: true,
output: { removeStyleLinkTypeAttributes: true,
path: paths.clientBuildDir, keepClosingSlash: true,
pathinfo: isDev, minifyJS: true,
filename: isProd ? minifyCSS: true,
'static/js/[name].[chunkhash:8].js' : "static/js/bundle.js", minifyURLs: true
chunkFilename: isProd ? }
'static/js/[name].[chunkhash:8].chunk.js' : "static/js/[name].chunk.js", : undefined
publicPath: publicPath, }),
devtoolModuleFilenameTemplate: isDev ? new FaviconsWebpackPlugin(
(info) => path.resolve(paths.clientDir, "images", "favicon-96x96.png")
"webpack://" + path.resolve(info.absoluteResourcePath).replace(/\\/g, "/") : undefined, ),
}, // Makes some environment variables available to the JS code, for example:
resolve: { // if (process.env.NODE_ENV === "production") { ... }. See `./env.js`.
extensions: [".ts", ".tsx", ".js", ".json", ".scss"], // It is absolutely essential that NODE_ENV was set to production here.
alias: { // Otherwise React will be compiled in the very slow development mode.
"@client": paths.clientDir, new webpack.DefinePlugin(environ.stringified),
"@common": paths.commonDir, new CaseSensitivePathsPlugin(),
} isProd &&
}, new UglifyJsPlugin({
module: { sourceMap: shouldUseSourceMap
rules: rules(env), }),
}, isDev && new webpack.HotModuleReplacementPlugin(),
plugins: plugins, new webpack.NamedModulesPlugin(),
optimization: { new ForkTsCheckerWebpackPlugin({
namedModules: isProd, checkSyntacticErrors: true,
}, tsconfig: paths.clientTsConfig,
devServer: { tslint: paths.tslintConfig
hot: true, }),
historyApiFallback: true, isDev && new DashboardPlugin(),
host: "0.0.0.0", new BundleAnalyzerPlugin({
port: 8081, analyzerMode: "static",
proxy: [{ openAnalyzer: false,
context: ["/api"], reportFilename: path.resolve(paths.serverBuildDir, "report.html")
target: paths.publicUrl, }),
}], new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/),
}, isProd &&
new MiniCssExtractPlugin({
filename: "static/css/[name].[chunkhash:8].css",
chunkFilename: "static/css/[id].[chunkhash:8].css"
})
].filter(Boolean);
return {
mode: isProd ? "production" : "development",
bail: isProd,
devtool: shouldUseSourceMap
? isProd
? "source-map"
: "inline-source-map"
: false,
entry: [
isDev && require.resolve("react-hot-loader/patch"),
isDev && require.resolve("react-dev-utils/webpackHotDevClient"),
require.resolve("./polyfills"),
paths.clientEntry
].filter(Boolean),
output: {
path: paths.clientBuildDir,
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", ".scss"],
alias: {
"@client": paths.clientDir,
"@common": paths.commonDir
}
},
module: {
rules: rules(env)
},
plugins: plugins,
optimization: {
namedModules: isProd
},
devServer: {
hot: true,
historyApiFallback: true,
host: "0.0.0.0",
port: 8081,
proxy: [
{
context: ["/api"],
target: paths.publicUrl
}
]
} }
}; };
});

37
package.json

@ -46,13 +46,13 @@
"express-promise-router": "^3.0.3", "express-promise-router": "^3.0.3",
"jsonwebtoken": "^8.3.0", "jsonwebtoken": "^8.3.0",
"lodash": "^4.17.10", "lodash": "^4.17.10",
"mobx": "^5.0.3", "mobx": "^5.1.0",
"mobx-utils": "^5.0.1", "mobx-utils": "^5.0.1",
"module-alias": "^2.1.0", "module-alias": "^2.1.0",
"moment": "^2.22.2", "moment": "^2.22.2",
"mqtt": "^2.18.3", "mqtt": "^2.18.8",
"pg": "^7.4.3", "pg": "^7.4.3",
"pino": "^5.2.0", "pino": "^5.4.0",
"pump": "^3.0.0", "pump": "^3.0.0",
"reflect-metadata": "^0.1.12", "reflect-metadata": "^0.1.12",
"serializr": "^1.3.0", "serializr": "^1.3.0",
@ -70,13 +70,13 @@
"@types/jsonwebtoken": "^7.2.8", "@types/jsonwebtoken": "^7.2.8",
"@types/lodash": "^4.14.116", "@types/lodash": "^4.14.116",
"@types/module-alias": "^2.0.0", "@types/module-alias": "^2.0.0",
"@types/node": "^10.7.1", "@types/node": "^10.9.4",
"@types/object-assign": "^4.0.30", "@types/object-assign": "^4.0.30",
"@types/pino": "^4.16.1", "@types/pino": "^5.20.0",
"@types/prop-types": "^15.5.5", "@types/prop-types": "^15.5.5",
"@types/pump": "^1.0.1", "@types/pump": "^1.0.1",
"@types/query-string": "^6.1.0", "@types/query-string": "^6.1.0",
"@types/react": "16.4.11", "@types/react": "16.4.13",
"@types/react-dom": "16.0.7", "@types/react-dom": "16.0.7",
"@types/react-hot-loader": "^4.1.0", "@types/react-hot-loader": "^4.1.0",
"@types/react-router-dom": "^4.3.0", "@types/react-router-dom": "^4.3.0",
@ -85,23 +85,23 @@
"@types/webpack-env": "^1.13.6", "@types/webpack-env": "^1.13.6",
"@types/ws": "^6.0.0", "@types/ws": "^6.0.0",
"async": "^2.6.1", "async": "^2.6.1",
"autoprefixer": "^9.1.2", "autoprefixer": "^9.1.3",
"cache-loader": "^1.2.2",
"case-sensitive-paths-webpack-plugin": "^2.1.2", "case-sensitive-paths-webpack-plugin": "^2.1.2",
"classnames": "^2.2.6", "classnames": "^2.2.6",
"css-loader": "^1.0.0", "css-loader": "^1.0.0",
"dotenv": "^6.0.0", "dotenv": "^6.0.0",
"favicons-webpack-plugin": "^0.0.9", "favicons-webpack-plugin": "^0.0.9",
"file-loader": "^1.1.11", "file-loader": "^2.0.0",
"font-awesome": "^4.7.0", "font-awesome": "^4.7.0",
"fork-ts-checker-webpack-plugin": "^0.4.9", "fork-ts-checker-webpack-plugin": "^0.4.9",
"happypack": "^5.0.0",
"html-webpack-plugin": "^3.2.0", "html-webpack-plugin": "^3.2.0",
"mini-css-extract-plugin": "^0.4.1", "mini-css-extract-plugin": "^0.4.2",
"mobx-react": "^5.2.5", "mobx-react": "^5.2.5",
"mobx-react-devtools": "^6.0.3", "mobx-react-devtools": "^6.0.3",
"mobx-react-router": "^4.0.4", "mobx-react-router": "^4.0.4",
"node-sass": "^4.9.3", "node-sass": "^4.9.3",
"nodemon": "^1.18.3", "nodemon": "^1.18.4",
"npm-run-all": "^4.1.3", "npm-run-all": "^4.1.3",
"object-assign": "^4.1.1", "object-assign": "^4.1.1",
"postcss-flexbugs-fixes": "^4.1.0", "postcss-flexbugs-fixes": "^4.1.0",
@ -111,31 +111,32 @@
"prop-types": "^15.6.2", "prop-types": "^15.6.2",
"query-string": "^6.1.0", "query-string": "^6.1.0",
"react": "16.4.2", "react": "16.4.2",
"react-dev-utils": "^5.0.1", "react-dev-utils": "^5.0.2",
"react-dom": "16.4.2", "react-dom": "16.4.2",
"react-hot-loader": "^4.3.4", "react-hot-loader": "^4.3.5",
"react-router": "^4.3.1", "react-router": "^4.3.1",
"react-router-dom": "^4.3.1", "react-router-dom": "^4.3.1",
"react-sortable-hoc": "^0.8.3", "react-sortable-hoc": "^0.8.3",
"sass-loader": "^7.1.0", "sass-loader": "^7.1.0",
"semantic-ui-css": "^2.3.3", "semantic-ui-css": "^2.3.3",
"semantic-ui-react": "^0.82.2", "semantic-ui-react": "^0.82.3",
"source-map-loader": "^0.2.4", "source-map-loader": "^0.2.4",
"style-loader": "^0.22.1", "style-loader": "^0.23.0",
"thread-loader": "^1.2.0",
"ts-loader": "^4.5.0", "ts-loader": "^4.5.0",
"tslint": "^5.11.0", "tslint": "^5.11.0",
"tslint-config-prettier": "^1.15.0", "tslint-config-prettier": "^1.15.0",
"tslint-consistent-codestyle": "^1.13.3", "tslint-consistent-codestyle": "^1.13.3",
"tslint-react": "^3.6.0", "tslint-react": "^3.6.0",
"typescript": "^3.0.1", "typescript": "^3.0.3",
"uglify-es": "^3.3.9", "uglify-es": "^3.3.9",
"uglifyjs-webpack-plugin": "^1.3.0", "uglifyjs-webpack-plugin": "^1.3.0",
"url-loader": "^1.1.1", "url-loader": "^1.1.1",
"webpack": "^4.16.5", "webpack": "^4.17.1",
"webpack-bundle-analyzer": "^2.13.1", "webpack-bundle-analyzer": "^2.13.1",
"webpack-cli": "^3.1.0", "webpack-cli": "^3.1.0",
"webpack-dashboard": "^2.0.0", "webpack-dashboard": "^2.0.0",
"webpack-dev-server": "^3.1.5" "webpack-dev-server": "^3.1.7"
}, },
"resolutions": { "resolutions": {
"**/@types/react": "16.4.11", "**/@types/react": "16.4.11",

1
paths.js

@ -19,6 +19,7 @@ function ensureSlash(p, needsSlash) {
exports.dotenv = resolveRoot(".env"); exports.dotenv = resolveRoot(".env");
exports.nodeModulesDir = resolveRoot("node_modules"); exports.nodeModulesDir = resolveRoot("node_modules");
exports.packageJson = resolveRoot("package.json"); exports.packageJson = resolveRoot("package.json");
exports.tslintConfig = resolveRoot("tslint.json");
exports.publicUrl = ensureSlash(process.env.PUBLIC_URL || "http://localhost:8080/", true); exports.publicUrl = ensureSlash(process.env.PUBLIC_URL || "http://localhost:8080/", true);
exports.publicPath = ensureSlash(url.parse(exports.publicUrl).pathname || "/", true); exports.publicPath = ensureSlash(url.parse(exports.publicUrl).pathname || "/", true);

629
yarn.lock

File diff suppressed because it is too large Load Diff
Loading…
Cancel
Save