[CORL-305] Speed up build process and upgrade dependencies (#2304)

* feat: speed up build process, upgrade majority of dependencies

* feat: allow specifying max cores

* chore: add some comments
This commit is contained in:
Kiwi
2019-05-07 20:22:19 +02:00
committed by GitHub
parent 98795d161d
commit ea6f42c256
18 changed files with 10385 additions and 4034 deletions
+1 -4
View File
@@ -18,10 +18,7 @@ module.exports = {
},
test: {
presets: [
[
"@babel/env",
{ targets: "last 2 versions, ie 11", modules: "commonjs" },
],
["@babel/env", { targets: "last 2 versions", modules: "commonjs" }],
"@babel/react",
],
plugins: ["dynamic-import-node"],
+11 -1
View File
@@ -1,4 +1,5 @@
import errorOverlayMiddleware from "react-dev-utils/errorOverlayMiddleware";
import evalSourceMapMiddleware from "react-dev-utils/evalSourceMapMiddleware";
import ignoredFiles from "react-dev-utils/ignoredFiles";
import noopServiceWorkerMiddleware from "react-dev-utils/noopServiceWorkerMiddleware";
import { Configuration } from "webpack-dev-server";
@@ -16,6 +17,12 @@ export default function({
publicPath,
}: WebpackDevServerConfig): Configuration {
return {
stats: {
// https://github.com/TypeStrong/ts-loader#transpileonly-boolean-defaultfalse
// Using transpilation only without typechecks gives warnings when we reexport types.
// We can ignore them here.
warningsFilter: /export .* was not found in/,
},
// Enable gzip compression of generated files.
compress: true,
// Silence WebpackDevServer's own logs since they're generally not useful.
@@ -73,7 +80,10 @@ export default function({
target: `http://localhost:${serverPort}`,
},
},
before(app: any) {
before(app, server) {
// 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());
// This service worker file is effectively a 'no-op' that will reset any
+9786 -3844
View File
File diff suppressed because it is too large Load Diff
+85 -82
View File
@@ -15,24 +15,27 @@
"npm": ">=6.7.0"
},
"bugs": "https://github.com/coralproject/talk/issues",
"contributors": "https://github.com/coralproject/talk/graphs/contributors",
"contributors": [
"https://github.com/coralproject/talk/graphs/contributors"
],
"description": "A better commenting experience from Mozilla, The Washington Post, and The New York Times.",
"scripts": {
"build": "npm-run-all generate --parallel build:*",
"build:client": "ts-node ./scripts/build.ts",
"build": "NODE_ENV=production WEBPACK_DISABLE_SOURCEMAPS=1 npm-run-all generate --parallel lint:client build:client build:server",
"build:development": "NODE_ENV=development npm-run-all generate --parallel lint:client build:client build:server",
"build:client": "TS_NODE_FILES=true ts-node ./scripts/build.ts",
"build:server": "gulp server",
"doctoc": "doctoc --title='## Table of Contents' --github README.md",
"generate": "npm-run-all --parallel generate:*",
"generate:css-types": "tcm src/core/client/",
"generate:relay-stream": "ts-node ./scripts/compileRelay --src ./src/core/client/stream --schema tenant",
"generate:relay-auth": "ts-node ./scripts/compileRelay --src ./src/core/client/auth --schema tenant",
"generate:relay-install": "ts-node ./scripts/compileRelay --src ./src/core/client/install --schema tenant",
"generate:relay-admin": "ts-node ./scripts/compileRelay --src ./src/core/client/admin --schema tenant",
"generate:relay-stream": "TTS_NODE_FILES=true S_NODE_FILES=true ts-node ./scripts/compileRelay --src ./src/core/client/stream --schema tenant",
"generate:relay-auth": "TS_NODE_FILES=true ts-node ./scripts/compileRelay --src ./src/core/client/auth --schema tenant",
"generate:relay-install": "TS_NODE_FILES=true ts-node ./scripts/compileRelay --src ./src/core/client/install --schema tenant",
"generate:relay-admin": "TS_NODE_FILES=true ts-node ./scripts/compileRelay --src ./src/core/client/admin --schema tenant",
"generate:schema": "node ./scripts/generateSchemaTypes.js",
"docz": "docz",
"start": "NODE_ENV=production node dist/index.js",
"start:development": "NODE_ENV=development CONCURRENCY=${CONCURRENCY:-2} TS_NODE_PROJECT=./src/tsconfig.json node -r ts-node/register -r tsconfig-paths/register ./src/index.ts",
"start:webpackDevServer": "ts-node ./scripts/start.ts",
"start:development": "NODE_ENV=development CONCURRENCY=${CONCURRENCY:-2} TS_NODE_FILES=true TS_NODE_PROJECT=./src/tsconfig.json node -r ts-node/register -r tsconfig-paths/register ./src/index.ts",
"start:webpackDevServer": "TS_NODE_FILES=true ts-node ./scripts/start.ts",
"lint": "npm-run-all --parallel lint:* tscheck:*",
"lint:server": "tslint --project ./src/tsconfig.json",
"lint:client": "tslint --project ./src/core/client/tsconfig.json",
@@ -44,7 +47,7 @@
"tscheck:server": "tsc --project ./src/tsconfig.json --noEmit",
"tscheck:client": "tsc --project ./src/core/client/tsconfig.json --noEmit",
"tscheck:scripts": "tsc --project ./tsconfig.json --noEmit",
"watch": "NODE_ENV=development ts-node ./scripts/watcher/bin/watcher.ts --config ./config/watcher.ts"
"watch": "NODE_ENV=development TS_NODE_FILES=true ts-node ./scripts/watcher/bin/watcher.ts --config ./config/watcher.ts"
},
"license": "Apache-2.0",
"dependencies": {
@@ -81,11 +84,11 @@
"html-to-text": "^4.0.0",
"ioredis": "^3.2.2",
"joi": "^13.4.0",
"jsdom": "^11.12.0",
"jsdom": "^15.0.0",
"jsonwebtoken": "^8.3.0",
"jwks-rsa": "^1.3.0",
"linkify-it": "^2.1.0",
"linkifyjs": "^2.1.7",
"linkifyjs": "^2.1.8",
"lodash": "^4.17.10",
"luxon": "^1.3.1",
"metascraper-author": "^3.11.8",
@@ -109,7 +112,7 @@
"permit": "^0.2.4",
"querystringify": "^2.1.0",
"react-relay-network-modern": "^2.4.0",
"source-map-support": "^0.5.10",
"source-map-support": "^0.5.12",
"stack-utils": "^1.0.2",
"striptags": "^3.1.1",
"throng": "^4.0.0",
@@ -118,11 +121,11 @@
"verror": "^1.10.0"
},
"devDependencies": {
"@babel/core": "^7.2.0",
"@babel/core": "^7.4.4",
"@babel/plugin-syntax-dynamic-import": "^7.2.0",
"@babel/plugin-transform-modules-commonjs": "^7.2.0",
"@babel/polyfill": "^7.0.0",
"@babel/preset-env": "^7.2.0",
"@babel/plugin-transform-modules-commonjs": "^7.4.4",
"@babel/polyfill": "^7.4.4",
"@babel/preset-env": "^7.4.4",
"@babel/preset-react": "^7.0.0",
"@coralproject/rte": "^0.10.13",
"@intervolga/optimize-cssnano-plugin": "^1.0.6",
@@ -131,10 +134,9 @@
"@types/bunyan": "^1.8.4",
"@types/case-sensitive-paths-webpack-plugin": "^2.1.2",
"@types/cheerio": "^0.22.8",
"@types/chokidar": "^1.7.5",
"@types/classnames": "^2.2.4",
"@types/classnames": "^2.2.7",
"@types/commander": "^2.12.2",
"@types/compression-webpack-plugin": "^0.4.2",
"@types/compression-webpack-plugin": "^2.0.0",
"@types/consolidate": "0.0.34",
"@types/convict": "^4.2.0",
"@types/cors": "^2.8.4",
@@ -152,10 +154,10 @@
"@types/ioredis": "^3.2.12",
"@types/jest": "^23.1.5",
"@types/joi": "^13.0.8",
"@types/jsdom": "^11.12.0",
"@types/jsdom": "^12.2.3",
"@types/jsonwebtoken": "^7.2.7",
"@types/linkify-it": "^2.0.4",
"@types/linkifyjs": "^2.1.0",
"@types/linkify-it": "^2.1.0",
"@types/linkifyjs": "^2.1.1",
"@types/lodash": "^4.14.118",
"@types/luxon": "^1.12.0",
"@types/marked": "^0.6.0",
@@ -163,7 +165,7 @@
"@types/mongodb": "^3.1.22",
"@types/ms": "^0.7.30",
"@types/node": "^10.5.2",
"@types/node-fetch": "^2.1.2",
"@types/node-fetch": "^2.3.3",
"@types/nodemailer": "^4.6.2",
"@types/nunjucks": "^3.0.0",
"@types/passport": "^0.4.6",
@@ -173,85 +175,87 @@
"@types/passport-strategy": "^0.2.33",
"@types/prop-types": "^15.5.8",
"@types/react": "^16.8.10",
"@types/react-copy-to-clipboard": "^4.2.5",
"@types/react-copy-to-clipboard": "^4.2.6",
"@types/react-dom": "^16.8.3",
"@types/react-relay": "^1.3.9",
"@types/react-responsive": "^3.0.1",
"@types/react-test-renderer": "^16.8.1",
"@types/react-transition-group": "^2.0.14",
"@types/recompose": "^0.26.5",
"@types/recompose": "0.26.5",
"@types/relay-runtime": "^1.3.6",
"@types/sane": "^2.0.0",
"@types/shallow-equals": "^1.0.0",
"@types/simplemde": "^1.11.7",
"@types/sinon": "^5.0.1",
"@types/source-map-support": "^0.4.1",
"@types/sinon": "^7.0.11",
"@types/source-map-support": "^0.5.0",
"@types/stack-utils": "^1.0.1",
"@types/throng": "^4.0.2",
"@types/tlds": "^1.199.0",
"@types/uuid": "^3.4.3",
"@types/uuid": "^3.4.4",
"@types/verror": "^1.10.3",
"@types/vinyl": "^2.0.2",
"@types/webpack": "^4.4.7",
"@types/webpack": "^4.4.31",
"@types/webpack-assets-manifest": "^3.0.0",
"@types/webpack-bundle-analyzer": "^2.13.0",
"@types/webpack-dev-server": "^2.9.5",
"@types/webpack-bundle-analyzer": "^2.13.1",
"@types/webpack-dev-server": "^3.1.5",
"@types/ws": "^5.1.2",
"autoprefixer": "^8.6.5",
"acorn": "^6.1.1",
"autoprefixer": "^9.5.1",
"babel-core": "^7.0.0-bridge.0",
"babel-jest": "^23.6.0",
"babel-loader": "^8.0.4",
"babel-loader": "^8.0.5",
"babel-plugin-dynamic-import-node": "^2.2.0",
"babel-plugin-lodash": "^3.3.4",
"babel-plugin-module-resolver": "^3.1.1",
"babel-plugin-module-resolver": "^3.2.0",
"babel-plugin-relay": "^1.7.0",
"babel-plugin-use-lodash-es": "^0.2.0",
"babel-preset-react-optimize": "^1.0.1",
"bowser": "^1.9.4",
"case-sensitive-paths-webpack-plugin": "^2.1.2",
"chalk": "^2.4.1",
"chokidar": "^2.0.4",
"classnames": "^2.2.5",
"commander": "^2.16.0",
"case-sensitive-paths-webpack-plugin": "^2.2.0",
"chalk": "^2.4.2",
"chokidar": "^3.0.0",
"classnames": "^2.2.6",
"commander": "^2.20.0",
"comment-json": "^1.1.3",
"compression-webpack-plugin": "^1.1.11",
"copy-webpack-plugin": "^4.5.1",
"compression-webpack-plugin": "^2.0.0",
"copy-webpack-plugin": "^5.0.3",
"cross-spawn": "^6.0.5",
"css-loader": "^1.0.1",
"del": "^3.0.0",
"del": "^4.1.1",
"doctoc": "^1.4.0",
"docz": "^0.13.7",
"docz-theme-default": "^0.13.7",
"enzyme": "^3.8.0",
"enzyme-adapter-react-16": "^1.7.1",
"enzyme": "^3.9.0",
"enzyme-adapter-react-16": "^1.12.1",
"enzyme-to-json": "^3.3.5",
"eventemitter2": "^5.0.1",
"final-form": "^4.8.1",
"flat": "^4.1.0",
"fluent-intl-polyfill": "^0.1.0",
"fluent-langneg": "^0.1.0",
"fluent-react": "^0.8.3",
"fluent-langneg": "^0.1.1",
"fluent-react": "^0.8.4",
"fork-ts-checker-webpack-plugin": "^1.3.0",
"graphql-schema-linter": "^0.2.0",
"graphql-schema-typescript": "^1.2.9",
"gulp": "^4.0.0",
"gulp": "^4.0.2",
"gulp-babel": "^8.0.0",
"gulp-cli": "^2.0.1",
"gulp-sourcemaps": "^2.6.4",
"gulp-typescript": "^5.0.0-alpha.3",
"gulp-cli": "^2.2.0",
"gulp-sourcemaps": "^2.6.5",
"gulp-typescript": "^5.0.1",
"html-webpack-plugin": "^4.0.0-beta.5",
"husky": "^1.1.0",
"intersection-observer": "^0.5.1",
"husky": "^2.2.0",
"intersection-observer": "^0.6.0",
"jest": "^23.4.1",
"jest-junit": "^5.1.0",
"jest-localstorage-mock": "^2.2.0",
"jest-mock-console": "^0.4.0",
"lint-staged": "^7.3.0",
"loader-utils": "^1.1.0",
"lint-staged": "^8.1.6",
"loader-utils": "^1.2.3",
"lodash-es": "^4.17.11",
"marked": "^0.6.0",
"material-design-icons": "^3.0.1",
"mini-css-extract-plugin": "^0.5.0",
"npm-run-all": "^4.1.3",
"mini-css-extract-plugin": "^0.6.0",
"npm-run-all": "^4.1.5",
"postcss-advanced-variables": "^3.0.0",
"postcss-css-variables": "^0.11.0",
"postcss-flexbugs-fixes": "^4.1.0",
@@ -262,14 +266,14 @@
"postcss-nested": "^4.1.1",
"postcss-prepend-imports": "^1.0.1",
"postcss-preset-env": "^6.5.0",
"prettier": "^1.16.4",
"prettier": "^1.17.0",
"prop-types": "^15.6.2",
"pstree.remy": "^1.1.0",
"pstree.remy": "^1.1.6",
"pym.js": "^1.3.2",
"raw-loader": "^0.5.1",
"react": "^16.8.4",
"react-copy-to-clipboard": "^5.0.1",
"react-dev-utils": "6.0.0-next.3e165448",
"react-dev-utils": "^9.0.0",
"react-dom": "^16.8.4",
"react-final-form": "^3.6.4",
"react-popper": "^1.3.2",
@@ -279,42 +283,41 @@
"react-timeago": "^4.1.9",
"react-transition-group": "^2.5.0",
"react-with-state-props": "^2.0.4",
"recompose": "^0.27.1",
"recompose": "0.27.1",
"relay-compiler": "^1.7.0-rc.1",
"relay-compiler-language-typescript": "^1.1.0",
"relay-local-schema": "^0.7.0",
"relay-runtime": "^1.7.0-rc.1",
"sane": "^4.0.2",
"sane": "^4.1.0",
"shallow-equals": "^1.0.0",
"simplemde": "^1.11.2",
"simulant": "^0.2.2",
"sinon": "^6.1.5",
"sinon": "^7.3.2",
"style-loader": "^0.23.1",
"terser-webpack-plugin": "^1.1.0",
"timekeeper": "^2.1.2",
"terser-webpack-plugin": "^1.2.3",
"thread-loader": "^2.1.2",
"timekeeper": "^2.2.0",
"ts-jest": "^23.0.0",
"ts-loader": "^4.4.2",
"ts-node": "^6.2.0",
"tsconfig-paths": "^3.4.2",
"tsconfig-paths-webpack-plugin": "^3.1.4",
"tslint": "^5.15.0",
"ts-loader": "^6.0.0",
"ts-node": "^8.1.0",
"tsconfig-paths": "^3.8.0",
"tsconfig-paths-webpack-plugin": "^3.2.0",
"tslint": "^5.16.0",
"tslint-config-prettier": "^1.18.0",
"tslint-loader": "^3.6.0",
"tslint-plugin-prettier": "^2.0.1",
"tslint-react": "^4.0.0",
"typed-css-modules": "^0.3.4",
"typeface-manuale": "0.0.54",
"typeface-source-sans-pro": "0.0.54",
"typed-css-modules": "^0.4.2",
"typeface-manuale": "^0.0.71",
"typeface-source-sans-pro": "^0.0.54",
"typescript": "3.3.4000",
"typescript-snapshots-plugin": "^1.2.0",
"wait-for-expect": "^1.1.0",
"webpack": "^4.27.1",
"typescript-snapshots-plugin": "^1.6.0",
"wait-for-expect": "^1.1.1",
"webpack": "^4.30.0",
"webpack-assets-manifest": "^3.1.1",
"webpack-bundle-analyzer": "^3.0.3",
"webpack-cli": "^3.1.2",
"webpack-dev-server": "^3.1.14",
"webpack-hot-client": "^4.1.1",
"whatwg-fetch": "^2.0.4"
"webpack-bundle-analyzer": "^3.3.2",
"webpack-cli": "^3.3.2",
"webpack-dev-server": "3.2.1",
"whatwg-fetch": "^3.0.0"
},
"husky": {
"hooks": {
+292
View File
@@ -0,0 +1,292 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
*
* This source code is licensed under the MIT license found in the
* LICENSE file in the root directory of this source tree.
*
* This file is taken from create-react-app.
* We disabled tty support, removed unessential parts to us and
* added support for `warningsFilter` and Multi Webpack Config.
*
* TODO: (cvle) The `forkTsCheckerWebpackPlugin` hooks are not working atm.
*/
"use strict";
// tslint:disable:no-console
const address = require("address");
const url = require("url");
const chalk = require("chalk");
const clearConsole = require("react-dev-utils/clearConsole");
const formatWebpackMessages = require("react-dev-utils/formatWebpackMessages");
const typescriptFormatter = require("react-dev-utils/typescriptFormatter");
const forkTsCheckerWebpackPlugin = require("react-dev-utils/ForkTsCheckerWebpackPlugin");
const Stats = require("webpack/lib/Stats");
// (cvle): Changed to false as we are sharing the tty with other processes.
// const isInteractive = process.stdout.isTTY && false;
const isInteractive = false;
function prepareUrls(protocol, host, port) {
const formatUrl = hostname =>
url.format({
protocol,
hostname,
port,
pathname: "/",
});
const prettyPrintUrl = hostname =>
url.format({
protocol,
hostname,
port: chalk.bold(port),
pathname: "/",
});
const isUnspecifiedHost = host === "0.0.0.0" || host === "::";
let prettyHost;
let lanUrlForConfig;
let lanUrlForTerminal;
if (isUnspecifiedHost) {
prettyHost = "localhost";
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 private, format it for later use
lanUrlForTerminal = prettyPrintUrl(lanUrlForConfig);
} else {
// Address is not private, so we will discard it
lanUrlForConfig = undefined;
}
}
} catch (_e) {
// ignored
}
} else {
prettyHost = host;
}
const localUrlForTerminal = prettyPrintUrl(prettyHost);
const localUrlForBrowser = formatUrl(prettyHost);
return {
lanUrlForConfig,
lanUrlForTerminal,
localUrlForTerminal,
localUrlForBrowser,
};
}
function printInstructions(appName, urls, useYarn) {
console.log();
console.log(`You can now view ${chalk.bold(appName)} in the browser.`);
console.log();
if (urls.lanUrlForTerminal) {
console.log(
` ${chalk.bold("Local:")} ${urls.localUrlForTerminal}`
);
console.log(
` ${chalk.bold("On Your Network:")} ${urls.lanUrlForTerminal}`
);
} else {
console.log(` ${urls.localUrlForTerminal}`);
}
console.log();
console.log("Note that the development build is not optimized.");
console.log(
`To create a production build, use ` +
`${chalk.cyan(`${useYarn ? "yarn" : "npm run"} build`)}.`
);
console.log();
}
function createCompiler({
appName,
config,
devSocket,
urls,
useYarn,
useTypeScript,
webpack,
}) {
// "Compiler" is a low-level interface to Webpack.
// It lets us listen to some events and provide our own custom messages.
let compiler;
try {
compiler = webpack(config);
} catch (err) {
console.log(chalk.red("Failed to compile."));
console.log();
console.log(err.message || err);
console.log();
process.exit(1);
}
// "invalid" event fires when you have changed a file, and Webpack is
// recompiling a bundle. WebpackDevServer takes care to pause serving the
// bundle, so if you refresh, it'll wait instead of serving the old one.
// "invalid" is short for "bundle invalidated", it doesn't imply any errors.
compiler.hooks.invalid.tap("invalid", () => {
if (isInteractive) {
clearConsole();
}
console.log("Compiling...");
});
let isFirstCompile = true;
let tsMessagesPromises = [];
if (useTypeScript) {
compiler.compilers.forEach(singleCompiler => {
let tsMessagesPromise;
let tsMessagesResolver;
singleCompiler.hooks.beforeCompile.tap("beforeCompile", () => {
tsMessagesPromise = new Promise(resolve => {
tsMessagesResolver = msgs => resolve(msgs);
});
tsMessagesPromises.push(tsMessagesPromise);
});
const tsCheckerHooks = forkTsCheckerWebpackPlugin.getCompilerHooks(
singleCompiler
);
// now access hooks just like before
// TODO: (cvle) this doesn't work currently.
tsCheckerHooks.waiting.tap("yourListenerName", () => {
console.log("waiting for typecheck results");
});
// TODO: (cvle) this doesn't work currently.
tsCheckerHooks.receive.tap(
"afterTypeScriptCheck",
(diagnostics, lints) => {
console.log("RECEIVED");
const allMsgs = [...diagnostics, ...lints];
const format = message =>
`${message.file}\n${typescriptFormatter(message, true)}`;
tsMessagesResolver({
errors: allMsgs.filter(msg => msg.severity === "error").map(format),
warnings: allMsgs
.filter(msg => msg.severity === "warning")
.map(format),
});
}
);
});
}
// "done" event fires when Webpack has finished recompiling the bundle.
// Whether or not you have warnings or errors, you will get this event.
compiler.hooks.done.tap("done", async stats => {
if (isInteractive) {
clearConsole();
}
// We have switched off the default Webpack output in WebpackDevServer
// options so we are going to "massage" the warnings and errors and present
// them in a readable focused way.
// We only construct the warnings and errors for speed:
// https://github.com/facebook/create-react-app/issues/4492#issuecomment-421959548
const statOptions = {
all: false,
warnings: true,
errors: true,
...config.stats,
};
if (Array.isArray(config)) {
statOptions.children = config.map(c => c.stats || {});
}
const statsData = stats.toJson(statOptions);
if (useTypeScript && statsData.errors.length === 0) {
const delayedMsg = setTimeout(() => {
console.log(
chalk.yellow(
"Files successfully emitted, waiting for typecheck results..."
)
);
}, 100);
// Get back all tscheck results.
const results = await Promise.all(tsMessagesPromises);
clearTimeout(delayedMsg);
results.forEach(msgs => {
statsData.errors.push(...msgs.errors);
statsData.warnings.push(...msgs.warnings);
// Push errors and warnings into compilation result
// to show them after page refresh triggered by user.
stats.compilation.errors.push(...msgs.errors);
stats.compilation.warnings.push(...msgs.warnings);
if (msgs.errors.length > 0) {
devSocket.errors(msgs.errors);
} else if (msgs.warnings.length > 0) {
devSocket.warnings(msgs.warnings);
}
});
if (isInteractive) {
clearConsole();
}
}
const messages = formatWebpackMessages(statsData);
const isSuccessful = !messages.errors.length && !messages.warnings.length;
if (isSuccessful) {
console.log(chalk.green("Compiled successfully!"));
}
if (isSuccessful && (isInteractive || isFirstCompile)) {
printInstructions(appName, urls, useYarn);
}
isFirstCompile = false;
// If errors exist, only show errors.
if (messages.errors.length) {
// Only keep the first error. Others are often indicative
// of the same problem, but confuse the reader with noise.
if (messages.errors.length > 1) {
messages.errors.length = 1;
}
console.log(chalk.red("Failed to compile.\n"));
console.log(messages.errors.join("\n\n"));
return;
}
// Show warnings if no errors were found.
if (messages.warnings.length) {
console.log(chalk.yellow("Compiled with warnings.\n"));
console.log(messages.warnings.join("\n\n"));
// Teach some ESLint tricks.
console.log(
"\nSearch for the " +
chalk.underline(chalk.yellow("keywords")) +
" to learn more about each warning."
);
console.log(
"To ignore, add " +
chalk.cyan("// eslint-disable-next-line") +
" to the line before.\n"
);
}
});
return compiler;
}
module.exports = {
createCompiler,
prepareUrls,
};
+15 -7
View File
@@ -19,12 +19,14 @@ import createWebpackConfig from "../src/core/build/createWebpackConfig";
// tslint:disable: no-console
// Enforce environment to be production.
config.validate().set("env", "production");
process.env.WEBPACK = "true";
process.env.BABEL_ENV = "production";
process.env.NODE_ENV = "production";
process.env.NODE_ENV = process.env.NODE_ENV || "production";
process.env.BABEL_ENV = process.env.NODE_ENV;
// Enforce environment to be NODE_ENV.
config.validate().set("env", process.env.NODE_ENV);
const isProduction = process.env.NODE_ENV === "production";
// Makes the script crash on unhandled rejections instead of silently
// ignoring them. In the future, promise rejections that are not handled will
@@ -102,7 +104,11 @@ measureFileSizesBeforeBuild(paths.appDistStatic)
// Create the production build and print the deployment instructions.
function build(previousFileSizes: any) {
console.log("Creating an optimized production build...");
if (isProduction) {
console.log("Creating an optimized production build...");
} else {
console.log("Creating development build...");
}
const webpackConfig = createWebpackConfig(config);
const compiler = webpack(webpackConfig);
return new Promise((resolve, reject) => {
@@ -110,7 +116,9 @@ function build(previousFileSizes: any) {
if (err) {
return reject(err);
}
const messages = formatWebpackMessages(stats.toJson({}));
const messages = formatWebpackMessages(
stats.toJson({ children: webpackConfig.map(c => c.stats || {}) as any })
);
if (messages.errors.length) {
// Only keep the first error. Others are often indicative
// of the same problem, but confuse the reader with noise.
+25 -6
View File
@@ -6,12 +6,9 @@ import dotenv from "dotenv";
dotenv.config();
import chalk from "chalk";
import {
createCompiler,
prepareUrls,
} from "react-dev-utils/WebpackDevServerUtils";
import webpack from "webpack";
import WebpackDevServer from "webpack-dev-server";
import { createCompiler, prepareUrls } from "./WebpackDevServerUtils";
import createDevServerConfig from "../config/webpackDevServer.config";
import config from "../src/core/build/config";
@@ -52,9 +49,31 @@ if (process.env.HOST) {
}
const urls = prepareUrls("http", HOST, PORT);
const webpackConfig = createWebpackConfig(config);
const webpackConfig = createWebpackConfig(config, { watch: true });
const devSocket = {
warnings: (warnings: any) =>
(devServer as any).sockWrite(
(devServer as any).sockets,
"warnings",
warnings
),
errors: (errors: any) =>
(devServer as any).sockWrite((devServer as any).sockets, "errors", errors),
};
// Create a webpack compiler that is configured with custom messages.
const compiler = createCompiler(webpack, webpackConfig, "Talk", urls);
const compiler = createCompiler({
webpack,
config: webpackConfig,
appName: "Talk",
urls,
// useTypeScript: true, /* This is currently not working, as the ForkTsCheckerWebpackPlugin hooks are not triggering for some reason */
useTypeScript: false, // This would
useYarn: false,
devSocket,
});
// Serve webpack assets generated by the compiler over a web sever.
const serverConfig = createDevServerConfig({
allowedHost: urls.lanUrlForConfig,
+7 -5
View File
@@ -81,11 +81,13 @@ export default class LongRunningExecutor implements Executor {
if (err) {
reject(err);
}
spawn.sync("kill", [
`-${signal}`,
this.process!.pid.toString(),
...kids.map(p => p.PID.toString()),
]);
if (kids) {
spawn.sync("kill", [
`-${signal}`,
this.process!.pid.toString(),
...kids,
]);
}
resolve();
});
});
+1 -1
View File
@@ -1,6 +1,6 @@
declare module "pstree.remy" {
export default function psTree(
pid: number,
callback: (err: Error, kids: Array<{ PID: number }>) => void
callback: (err: Error, kids: string[]) => void
): void;
}
+7
View File
@@ -56,6 +56,13 @@ const config = convict({
env: "WEBPACK_TREESHAKE",
arg: "enableTreeShake",
},
maxCores: {
doc: "Set maximum of available cores",
format: "nat",
default: require("os").cpus().length,
env: "WEBPACK_MAX_CORES",
arg: "maxCores",
},
});
export type Config = typeof config;
+116 -81
View File
@@ -1,10 +1,12 @@
import OptimizeCssnanoPlugin from "@intervolga/optimize-cssnano-plugin";
import CaseSensitivePathsPlugin from "case-sensitive-paths-webpack-plugin";
import CompressionPlugin from "compression-webpack-plugin";
import ForkTsCheckerWebpackPlugin from "fork-ts-checker-webpack-plugin";
import HtmlWebpackPlugin from "html-webpack-plugin";
import { identity } from "lodash";
import MiniCssExtractPlugin from "mini-css-extract-plugin";
import path from "path";
import typescriptFormatter from "react-dev-utils/typescriptFormatter";
import WatchMissingNodeModulesPlugin from "react-dev-utils/WatchMissingNodeModulesPlugin";
import TerserPlugin from "terser-webpack-plugin";
import TsconfigPathsPlugin from "tsconfig-paths-webpack-plugin";
@@ -30,14 +32,16 @@ const filterPlugins = (plugins: Array<Plugin | null>): Plugin[] =>
interface CreateWebpackOptions {
appendPlugins?: any[];
watch?: boolean;
}
const publicPath = "/";
export default function createWebpackConfig(
config: Config,
{ appendPlugins = [] }: CreateWebpackOptions = {}
{ appendPlugins = [], watch = false }: CreateWebpackOptions = {}
): Configuration[] {
const maxCores = config.get("maxCores");
const env = createClientEnv(config);
const disableSourcemaps = config.get("disableSourcemaps");
const generateReport = config.get("generateReport");
@@ -59,24 +63,20 @@ export default function createWebpackConfig(
};
/**
* ifProduction will only include the nodes if we're in production mode.
* ifWatch will only include the nodes if we're in watch mode.
*/
const ifProduction = isProduction
? (...nodes: any[]) => nodes
: (...nodes: any[]) => [];
const ifWatch = watch ? (...nodes: any[]) => nodes : () => [];
/**
* ifNotProduction will only include the nodes if we're not in production
* mode.
* ifBuild will only include the nodes if we're in build mode.
*/
const ifNotProduction = !isProduction
? (...nodes: any[]) => nodes
: (...nodes: any[]) => [];
const ifBuild = !watch ? (...nodes: any[]) => nodes : () => [];
const styleLoader = {
loader: require.resolve("style-loader"),
options: {
hmr: !isProduction,
sourceMap: !disableSourcemaps,
hmr: watch,
},
};
@@ -102,14 +102,19 @@ export default function createWebpackConfig(
// availableLocales: ["en-US"],
};
const additionalPlugins = isProduction
? [
new MiniCssExtractPlugin({
filename: "assets/css/[name].[hash].css",
chunkFilename: "assets/css/[id].[hash].css",
}),
const additionalPlugins = [
...ifBuild(
new MiniCssExtractPlugin({
filename: isProduction
? "assets/css/[name].[hash].css"
: "assets/css/[name].css",
chunkFilename: isProduction
? "assets/css/[id].[hash].css"
: "assets/css/[id].css",
}),
isProduction &&
new OptimizeCssnanoPlugin({
sourceMap: true,
sourceMap: !disableSourcemaps,
cssnanoOptions: {
preset: [
"default",
@@ -121,26 +126,31 @@ export default function createWebpackConfig(
],
},
}),
// Pre-compress all the assets as they will be served as is.
new CompressionPlugin({}),
]
: [
// Add module names to factory functions so they appear in browser profiler.
new webpack.NamedModulesPlugin(),
// This is necessary to emit hot updates (currently CSS only):
new webpack.HotModuleReplacementPlugin(),
// Watcher doesn't work well if you mistype casing in a path so we use
// a plugin that prints an error when you attempt to do this.
// See https://github.com/facebookincubator/create-react-app/issues/240
new CaseSensitivePathsPlugin(),
// 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/facebookincubator/create-react-app/issues/186
new WatchMissingNodeModulesPlugin(paths.appNodeModules),
];
// Pre-compress all the assets as they will be served as is.
new CompressionPlugin({})
),
...ifWatch(
// Add module names to factory functions so they appear in browser profiler.
new webpack.NamedModulesPlugin(),
// Watcher doesn't work well if you mistype casing in a path so we use
// a plugin that prints an error when you attempt to do this.
// See https://github.com/facebookincubator/create-react-app/issues/240
new CaseSensitivePathsPlugin(),
// 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/facebookincubator/create-react-app/issues/186
new WatchMissingNodeModulesPlugin(paths.appNodeModules)
),
];
const baseConfig: Configuration = {
stats: {
// https://github.com/TypeStrong/ts-loader#transpileonly-boolean-defaultfalse
// Using transpilation only without typechecks gives warnings when we reexport types.
// We can ignore them here.
warningsFilter: /export .* was not found in/,
},
// Set webpack mode.
mode: isProduction ? "production" : "development",
optimization: {
@@ -182,14 +192,15 @@ export default function createWebpackConfig(
}),
],
},
devtool:
!disableSourcemaps && isProduction
? // We generate sourcemaps in production. This is slow but gives good results.
// You can exclude the *.map files from the build during deployment.
"source-map"
: // You may want 'eval' instead if you prefer to see the compiled output in DevTools.
// See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.
"cheap-module-source-map",
devtool: disableSourcemaps
? false
: isProduction
? // We generate sourcemaps in production. This is slow but gives good results.
// You can exclude the *.map files from the build during deployment.
"source-map"
: // You may want 'eval' instead if you prefer to see the compiled output in DevTools.
// See the discussion in https://github.com/facebookincubator/create-react-app/issues/343.
"cheap-module-source-map",
// These are the "entry points" to our application.
// This means they will be the "root" imports that are included in JS bundle.
// The first two entry points enable "hot" CSS and auto-refreshes for JS.
@@ -229,26 +240,13 @@ export default function createWebpackConfig(
modules: ["node_modules", paths.appLoaders],
},
module: {
strictExportPresence: true,
// https://github.com/TypeStrong/ts-loader#transpileonly-boolean-defaultfalse
// Using transpilation only without typechecks gives warnings when we reexport types
// thus we can't turn on `strictExportPresence` which would turn warnings into errors.
strictExportPresence: false,
rules: [
// Disable require.ensure as it's not a standard language feature.
{ parser: { requireEnsure: false } },
// First, run the linter.
// It's important to do this before Babel processes the JS.
{
test: /\.(js|ts|tsx)$/,
enforce: "pre",
use: [
{
options: {
tsConfigFile: paths.appTsconfig,
},
loader: require.resolve("tslint-loader"),
},
],
include: paths.appSrc,
},
{
// "oneOf" will traverse all following loaders until one will
// match the requirements. When no loader matches it will fall
@@ -331,7 +329,9 @@ export default function createWebpackConfig(
loader: require.resolve("url-loader"),
options: {
limit: 10000,
name: "assets/media/[name].[hash:8].[ext]",
name: isProduction
? "assets/media/[name].[hash:8].[ext]"
: "assets/media/[name].[ext]",
},
},
// Process JS with Babel.
@@ -339,6 +339,14 @@ export default function createWebpackConfig(
test: /\.(ts|tsx)$/,
include: paths.appSrc,
use: [
{
loader: "thread-loader",
options: {
// there should be 1 cpu for the fork-ts-checker-webpack-plugin
workers: maxCores - 1,
poolTimeout: watch ? Infinity : 500, // set this to Infinity in watch mode - see https://github.com/webpack-contrib/thread-loader
},
},
{
loader: require.resolve("babel-loader"),
options: {
@@ -357,12 +365,14 @@ export default function createWebpackConfig(
module: "esnext",
jsx: "preserve",
noEmit: false,
sourceMap: !disableSourcemaps,
},
transpileOnly: true,
// Overwrites the behavior of `include` and `exclude` to only
// include files that are actually being imported and which
// are necessary to compile the bundle.
onlyCompileBundledFiles: true,
happyPackMode: true, // IMPORTANT! use happyPackMode mode to speed-up compilation and reduce errors reported to webpack
},
},
],
@@ -381,7 +391,7 @@ export default function createWebpackConfig(
presets: [
[
"@babel/env",
{ targets: "last 2 versions, ie 11", modules: false },
{ targets: "last 2 versions", modules: false },
],
],
cacheDirectory: true,
@@ -392,19 +402,19 @@ export default function createWebpackConfig(
// "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, and
// in development "style" loader enables hot editing of CSS.
// When building we use a plugin to extract that CSS to a file, and
// in watch mode "style" loader enables hot editing of CSS.
{
test: /\.css$/,
use: [
isProduction ? MiniCssExtractPlugin.loader : styleLoader,
!watch ? MiniCssExtractPlugin.loader : styleLoader,
{
loader: require.resolve("css-loader"),
options: {
modules: true,
importLoaders: 1,
localIdentName: "[name]-[local]-[hash:base64:5]",
sourceMap: isProduction && !disableSourcemaps,
sourceMap: !disableSourcemaps,
},
},
{
@@ -413,13 +423,14 @@ export default function createWebpackConfig(
config: {
path: paths.appPostCssConfig,
},
sourceMap: !disableSourcemaps,
},
},
],
},
// "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.
// When building, 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.
{
@@ -430,7 +441,9 @@ export default function createWebpackConfig(
exclude: [/\.(js|ts|tsx)$/, /\.html$/, /\.json$/],
loader: require.resolve("file-loader"),
options: {
name: "assets/media/[name].[hash:8].[ext]",
name: isProduction
? "assets/media/[name].[hash:8].[ext]"
: "assets/media/[name].[ext]",
},
},
],
@@ -440,6 +453,25 @@ export default function createWebpackConfig(
],
},
plugins: [
// TODO: (cvle) this should work in build too but for some reasons it terminates the build afterwards.
// Preventing from running post build steps.
...ifWatch(
// We run tslint in a separate process to have a quicker build.
new ForkTsCheckerWebpackPlugin({
tslint: true,
typescript: require.resolve("typescript"),
async: true,
// TODO: (cvle) For some reason if incremental build is turned on it does not find lint errors during initial build.
useTypescriptIncrementalApi: false,
checkSyntacticErrors: true,
tsconfig: paths.appTsconfig,
watch: paths.appSrc,
// TODO: (cvle) ForkTsCheckerWebpackPlugin are currently not working, so we resort to default reporting.
silent: false,
// The formatter is normally invoked directly in WebpackDevServerUtils during development
formatter: typescriptFormatter,
})
),
// Makes some environment variables available to the JS code, for example:
// if (process.env.NODE_ENV === 'development') { ... }. See `./env.js`.
new webpack.DefinePlugin(envStringified),
@@ -470,7 +502,7 @@ export default function createWebpackConfig(
},
};
const devServerEntries = isProduction
const devServerEntries = !watch
? []
: [
// Include an alternative client for WebpackDevServer. A client's job is to
@@ -494,41 +526,45 @@ export default function createWebpackConfig(
stream: [
// We ship polyfills by default
paths.appPolyfill,
...ifProduction(paths.appPublicPath),
...ifBuild(paths.appPublicPath),
...devServerEntries,
paths.appStreamIndex,
],
auth: [
// We ship polyfills by default
paths.appPolyfill,
...ifProduction(paths.appPublicPath),
...ifBuild(paths.appPublicPath),
...devServerEntries,
paths.appAuthIndex,
// Remove deactivated entries.
],
authCallback: [
...ifProduction(paths.appPublicPath),
...ifBuild(paths.appPublicPath),
...devServerEntries,
paths.appAuthCallbackIndex,
],
install: [
// We ship polyfills by default
paths.appPolyfill,
...ifProduction(paths.appPublicPath),
...ifBuild(paths.appPublicPath),
...devServerEntries,
paths.appInstallIndex,
],
admin: [
// We ship polyfills by default
paths.appPolyfill,
...ifProduction(paths.appPublicPath),
...ifBuild(paths.appPublicPath),
...devServerEntries,
paths.appAdminIndex,
],
},
plugins: filterPlugins([
...baseConfig.plugins!,
...ifNotProduction(
...ifWatch(
// This is necessary to emit hot updates
new webpack.HotModuleReplacementPlugin({
multiStep: true,
}),
// Generates an `stream.html` file with the <script> injected.
new HtmlWebpackPlugin({
filename: "stream.html",
@@ -565,7 +601,7 @@ export default function createWebpackConfig(
inject: "body",
})
),
...ifProduction(
...ifBuild(
new WebpackAssetsManifest({
output: "asset-manifest.json",
entrypoints: true,
@@ -590,7 +626,6 @@ export default function createWebpackConfig(
entry: [
/* Use minimal amount of polyfills (for IE) */
"intersection-observer", // also for Safari
...devServerEntries,
paths.appEmbedIndex,
],
output: {
@@ -602,7 +637,7 @@ export default function createWebpackConfig(
},
plugins: filterPlugins([
...baseConfig.plugins!,
...ifNotProduction(
...ifWatch(
// Generates an `embed.html` file with the <script> injected.
new HtmlWebpackPlugin({
filename: "embed.html",
@@ -620,7 +655,7 @@ export default function createWebpackConfig(
inject: "head",
})
),
...ifProduction(
...ifBuild(
new WebpackAssetsManifest({
output: "embed-asset-manifest.json",
entrypoints: true,
+1 -1
View File
@@ -2,7 +2,7 @@ const lodashOptimizations = ["use-lodash-es", "lodash"];
module.exports = {
presets: [
["@babel/env", { targets: "last 2 versions, ie 11", modules: false }],
["@babel/env", { targets: "last 2 versions", modules: false }],
"@babel/react",
],
plugins: ["@babel/syntax-dynamic-import"],
@@ -13,7 +13,9 @@ import { ConfigureQueryLocal as Local } from "talk-stream/__generated__/Configur
import { Delay, Spinner } from "talk-ui/components";
const loadConfigureContainer = () =>
import("../containers/ConfigureContainer" /* webpackChunkName: "configure" */);
import(
"../containers/ConfigureContainer" /* webpackChunkName: "configure" */
);
// (cvle) For some reason without `setTimeout` this request will block other requests.
const preloadConfigureContainer = once(() =>
setTimeout(loadConfigureContainer)
+23
View File
@@ -36,6 +36,19 @@
format("woff");
}
@font-face {
font-family: "Source Sans Pro";
font-style: normal;
font-display: block;
font-weight: 700;
src: local("Source Sans Pro SemiBold italic"),
local("Source Sans Pro-SemiBolditalic"),
url("typeface-source-sans-pro/files/source-sans-pro-latin-700.woff2")
format("woff2"),
url("typeface-source-sans-pro/files/source-sans-pro-latin-700.woff")
format("woff");
}
@font-face {
font-family: "Manuale";
font-style: normal;
@@ -56,6 +69,16 @@
url("typeface-manuale/files/manuale-latin-600.woff") format("woff");
}
@font-face {
font-family: "Manuale";
font-style: normal;
font-display: block;
font-weight: 700;
src: local("Manuale SemiBold "), local("Manuale-SemiBold"),
url("typeface-manuale/files/manuale-latin-700.woff2") format("woff2"),
url("typeface-manuale/files/manuale-latin-700.woff") format("woff");
}
.heading1 {
@mixin heading1;
}
+1 -1
View File
@@ -1,5 +1,5 @@
module.exports = {
presets: [
["@babel/env", { targets: "last 2 versions, ie 11", modules: "commonjs" }],
["@babel/env", { targets: { node: "10.0.0" }, modules: "commonjs" }],
],
};
+2
View File
@@ -26,3 +26,5 @@ declare module "react-dev-utils/WebpackDevServerUtils";
declare module "react-dev-utils/FileSizeReporter";
declare module "react-dev-utils/formatWebpackMessages";
declare module "react-dev-utils/printBuildError";
declare module "react-dev-utils/typescriptFormatter";
declare module "react-dev-utils/evalSourceMapMiddleware";
+8
View File
@@ -0,0 +1,8 @@
/**
* This file contains the dynamic part of `tslint`.
*/
module.exports = {
// Decrease default linting severity during development.
defaultSeverity: process.env.NODE_ENV === "development" ? "warning" : "error",
};
+1
View File
@@ -1,5 +1,6 @@
{
"extends": [
"./tslint.dynamic.js",
"tslint:recommended",
"tslint-config-prettier",
"tslint-plugin-prettier"