From 234e7bc0c0f9aed2582f388b1bbdb89973a7f83d Mon Sep 17 00:00:00 2001 From: Angelo Abdoelsamath Date: Wed, 15 Jul 2020 10:28:07 +0200 Subject: [PATCH] Fast refresh implementation. --- package.json | 3 +- packages/client/config/webpack.config.js | 85 +++++++++--------------- packages/client/package.json | 2 + packages/client/src/index.tsx | 1 - yarn.lock | 45 ++++++++++++- 5 files changed, 79 insertions(+), 57 deletions(-) diff --git a/package.json b/package.json index 6cef3e9..1bfcda8 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,8 @@ }, "private": true, "scripts": { - "start": "yarn workspace @anche/textmate-grammar-parser run build && yarn workspace @anche/tmtheme-client run start", + "start": "yarn workspace @anche/textmate-grammar-parser run build && yarn start:editor", + "start:editor": "yarn workspace @anche/tmtheme-client run start", "format": "prettier --write \"packages/*/src/**/*.{ts,tsx,scss,js,json}\"" }, "husky": { diff --git a/packages/client/config/webpack.config.js b/packages/client/config/webpack.config.js index 18181b8..9571496 100644 --- a/packages/client/config/webpack.config.js +++ b/packages/client/config/webpack.config.js @@ -41,9 +41,7 @@ const shouldInlineRuntimeChunk = process.env.INLINE_RUNTIME_CHUNK !== 'false'; const isExtendingEslintConfig = process.env.EXTEND_ESLINT === 'true'; -const imageInlineSizeLimit = parseInt( - process.env.IMAGE_INLINE_SIZE_LIMIT || '10000' -); +const imageInlineSizeLimit = parseInt(process.env.IMAGE_INLINE_SIZE_LIMIT || '10000'); // Check if TypeScript is setup const useTypeScript = fs.existsSync(paths.appTsConfig); @@ -62,8 +60,7 @@ module.exports = function (webpackEnv) { // Variable used for enabling profiling in Production // passed into alias object. Uses a flag if passed into the build command - const isEnvProductionProfile = - isEnvProduction && process.argv.includes('--profile'); + const isEnvProductionProfile = isEnvProduction && process.argv.includes('--profile'); // We will provide `paths.publicUrlOrPath` to our app // as %PUBLIC_URL% in `index.html` and `process.env.PUBLIC_URL` in JavaScript. @@ -79,9 +76,7 @@ module.exports = function (webpackEnv) { loader: MiniCssExtractPlugin.loader, // css is located in `static/css`, use '../../' to locate index.html folder // in production `paths.publicUrlOrPath` can be a relative path - options: paths.publicUrlOrPath.startsWith('.') - ? { publicPath: '../../' } - : {}, + options: paths.publicUrlOrPath.startsWith('.') ? { publicPath: '../../' } : {}, }, { loader: require.resolve('css-loader'), @@ -126,7 +121,7 @@ module.exports = function (webpackEnv) { options: { sourceMap: true, }, - } + }, ); } return loaders; @@ -154,8 +149,8 @@ module.exports = function (webpackEnv) { // the line below with these two lines if you prefer the stock client: // require.resolve('webpack-dev-server/client') + '?/', // require.resolve('webpack/hot/dev-server'), - isEnvDevelopment && - require.resolve('react-dev-utils/webpackHotDevClient'), + // isEnvDevelopment && + // require.resolve('react-dev-utils/webpackHotDevClient'), // Finally, this is your app's code: paths.appIndexJs, // We include the app code last so that if there is a runtime error during @@ -184,13 +179,8 @@ module.exports = function (webpackEnv) { publicPath: paths.publicUrlOrPath, // Point sourcemap entries to original disk location (format as URL on Windows) devtoolModuleFilenameTemplate: isEnvProduction - ? (info) => - path - .relative(paths.appSrc, info.absoluteResourcePath) - .replace(/\\/g, '/') - : isEnvDevelopment && - ((info) => - path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')), + ? info => path.relative(paths.appSrc, info.absoluteResourcePath).replace(/\\/g, '/') + : isEnvDevelopment && (info => path.resolve(info.absoluteResourcePath).replace(/\\/g, '/')), // Prevents conflicts when multiple webpack runtimes (from different apps) // are used on the same page. jsonpFunction: `webpackJsonp${appPackageJson.name}`, @@ -273,7 +263,7 @@ module.exports = function (webpackEnv) { // https://twitter.com/wSokra/status/969679223278505985 // https://github.com/facebook/create-react-app/issues/5358 runtimeChunk: { - name: (entrypoint) => `runtime-${entrypoint.name}`, + name: entrypoint => `runtime-${entrypoint.name}`, }, }, resolve: { @@ -281,9 +271,7 @@ module.exports = function (webpackEnv) { // We placed these paths second because we want `node_modules` to "win" // if there are any conflicts. This matches Node resolution mechanism. // https://github.com/facebook/create-react-app/issues/253 - modules: ['node_modules', paths.appNodeModules].concat( - modules.additionalModulePaths || [] - ), + modules: ['node_modules', paths.appNodeModules].concat(modules.additionalModulePaths || []), // 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: @@ -291,8 +279,8 @@ module.exports = function (webpackEnv) { // `web` extension prefixes have been added for better support // for React Native Web. extensions: paths.moduleFileExtensions - .map((ext) => `.${ext}`) - .filter((ext) => useTypeScript || !ext.includes('ts')), + .map(ext => `.${ext}`) + .filter(ext => useTypeScript || !ext.includes('ts')), alias: { // Support React Native Web // https://www.smashingmagazine.com/2016/08/a-glimpse-into-the-future-with-react-native-for-web/ @@ -314,7 +302,7 @@ module.exports = function (webpackEnv) { // 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]), - ], + ].filter(Boolean), }, resolveLoader: { plugins: [ @@ -354,23 +342,21 @@ module.exports = function (webpackEnv) { include: paths.appSrc, loader: require.resolve('babel-loader'), options: { - customize: require.resolve( - 'babel-preset-react-app/webpack-overrides' - ), + customize: require.resolve('babel-preset-react-app/webpack-overrides'), plugins: [ + isEnvDevelopment && require.resolve('react-refresh/babel'), [ require.resolve('babel-plugin-named-asset-import'), { loaderMap: { svg: { - ReactComponent: - '@svgr/webpack?-svgo,+titleProp,+ref![path]', + ReactComponent: '@svgr/webpack?-svgo,+titleProp,+ref![path]', }, }, }, ], - ], + ].filter(Boolean), // This is a feature of `babel-loader` for webpack (not Babel itself). // It enables caching results in ./node_modules/.cache/babel-loader/ // directory for faster rebuilds. @@ -391,10 +377,7 @@ module.exports = function (webpackEnv) { configFile: false, compact: false, presets: [ - [ - require.resolve('babel-preset-react-app/dependencies'), - { helpers: true }, - ], + [require.resolve('babel-preset-react-app/dependencies'), { helpers: true }], ], cacheDirectory: true, // See #6846 for context on why cacheCompression is disabled @@ -435,12 +418,7 @@ module.exports = function (webpackEnv) { importLoaders: 1, sourceMap: isEnvProduction && shouldUseSourceMap, modules: { - getLocalIdent: ( - context, - localIdentName, - localName, - options - ) => { + getLocalIdent: (context, localIdentName, localName, options) => { return `${localIdentName}-[hash:base64:5]`; }, }, @@ -457,7 +435,7 @@ module.exports = function (webpackEnv) { importLoaders: 3, sourceMap: isEnvProduction && shouldUseSourceMap, }, - 'sass-loader' + 'sass-loader', ), // Don't consider CSS imports dead code even if the // containing package claims to have no side effects. @@ -477,7 +455,7 @@ module.exports = function (webpackEnv) { localIdentName: '[path][name]__[local]--[hash:base64:5]', }, }, - 'sass-loader' + 'sass-loader', ), }, // "file" loader makes sure those assets get served by WebpackDevServer. @@ -526,9 +504,15 @@ module.exports = function (webpackEnv) { minifyURLs: true, }, } - : undefined - ) + : undefined, + ), ), + isEnvDevelopment && + new ReactRefreshWebpackPlugin({ + overlay: { + entry: require.resolve('react-dev-utils/webpackHotDevClient'), + }, + }), // Inlines the webpack runtime script. This script is too small to warrant // a network request. // https://github.com/facebook/create-react-app/issues/5358 @@ -560,8 +544,7 @@ module.exports = function (webpackEnv) { // 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 - isEnvDevelopment && - new WatchMissingNodeModulesPlugin(paths.appNodeModules), + isEnvDevelopment && new WatchMissingNodeModulesPlugin(paths.appNodeModules), isEnvProduction && new MiniCssExtractPlugin({ // Options similar to the same options in webpackOptions.output @@ -583,9 +566,7 @@ module.exports = function (webpackEnv) { manifest[file.name] = file.path; return manifest; }, seed); - const entrypointFiles = entrypoints.main.filter( - (fileName) => !fileName.endsWith('.map') - ); + const entrypointFiles = entrypoints.main.filter(fileName => !fileName.endsWith('.map')); return { files: manifestFiles, @@ -626,9 +607,7 @@ module.exports = function (webpackEnv) { async: isEnvDevelopment, useTypescriptIncrementalApi: true, checkSyntacticErrors: true, - resolveModuleNameModule: process.versions.pnp - ? `${__dirname}/pnpTs.js` - : undefined, + resolveModuleNameModule: process.versions.pnp ? `${__dirname}/pnpTs.js` : undefined, resolveTypeReferenceDirectiveModule: process.versions.pnp ? `${__dirname}/pnpTs.js` : undefined, diff --git a/packages/client/package.json b/packages/client/package.json index 3dc2550..6e37d79 100644 --- a/packages/client/package.json +++ b/packages/client/package.json @@ -65,6 +65,7 @@ }, "devDependencies": { "@babel/core": "7.9.0", + "@pmmmwh/react-refresh-webpack-plugin": "^0.3.3", "@svgr/webpack": "4.3.3", "@testing-library/jest-dom": "^4.2.4", "@testing-library/react": "^9.3.2", @@ -104,6 +105,7 @@ "postcss-normalize": "8.0.1", "postcss-preset-env": "6.7.0", "postcss-safe-parser": "4.0.1", + "react-refresh": "^0.8.3", "resolve-url-loader": "3.1.1", "rimraf": "^3.0.2", "sass-loader": "8.0.2", diff --git a/packages/client/src/index.tsx b/packages/client/src/index.tsx index cb7ab1c..390e4d6 100644 --- a/packages/client/src/index.tsx +++ b/packages/client/src/index.tsx @@ -2,7 +2,6 @@ import React, { Profiler } from 'react'; // eslint-disable-next-line @typescript-eslint/ban-ts-ignore // @ts-ignore import ReactDOM from 'react-dom'; -import { unstable_trace as trace } from 'scheduler/tracing'; import App from './App'; diff --git a/yarn.lock b/yarn.lock index 8a3c812..add819d 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2619,6 +2619,18 @@ dependencies: "@types/node" ">= 8" +"@pmmmwh/react-refresh-webpack-plugin@^0.3.3": + version "0.3.3" + resolved "https://registry.yarnpkg.com/@pmmmwh/react-refresh-webpack-plugin/-/react-refresh-webpack-plugin-0.3.3.tgz#40a3d674f42a011b7f30a9609aa8fb68ec3c39c9" + integrity sha512-uc6FmPEegAZawSHjUMFQwU7EjaDn7zy1iD/KD/wBROL9F4378OES8MKMYHoRAKT61Fk7LxVKZSDR5VespMQiqw== + dependencies: + ansi-html "^0.0.7" + error-stack-parser "^2.0.6" + html-entities "^1.2.1" + lodash.debounce "^4.0.8" + native-url "^0.2.6" + schema-utils "^2.6.5" + "@sheerun/mutationobserver-shim@^0.3.2": version "0.3.3" resolved "https://registry.yarnpkg.com/@sheerun/mutationobserver-shim/-/mutationobserver-shim-0.3.3.tgz#5405ee8e444ed212db44e79351f0c70a582aae25" @@ -3454,7 +3466,7 @@ ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: dependencies: type-fest "^0.11.0" -ansi-html@0.0.7: +ansi-html@0.0.7, ansi-html@^0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/ansi-html/-/ansi-html-0.0.7.tgz#813584021962a9e9e6fd039f940d12f56ca7859e" integrity sha1-gTWEAhliqenm/QOflA0S9WynhZ4= @@ -6263,6 +6275,13 @@ error-ex@^1.2.0, error-ex@^1.3.1: dependencies: is-arrayish "^0.2.1" +error-stack-parser@^2.0.6: + version "2.0.6" + resolved "https://registry.yarnpkg.com/error-stack-parser/-/error-stack-parser-2.0.6.tgz#5a99a707bd7a4c58a797902d48d82803ede6aad8" + integrity sha512-d51brTeqC+BHlwF0BhPtcYgF5nlzf9ZZ0ZIUQNZpc9ZB9qw5IJ2diTrBY9jlCJkTLITYPjmiX6OWCwH+fuyNgQ== + dependencies: + stackframe "^1.1.1" + es-abstract@^1.17.0, es-abstract@^1.17.0-next.1, es-abstract@^1.17.2, es-abstract@^1.17.5: version "1.17.5" resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.17.5.tgz#d8c9d1d66c8981fb9200e2251d799eee92774ae9" @@ -9813,6 +9832,11 @@ lodash.clonedeep@^4.5.0: resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= +lodash.debounce@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/lodash.debounce/-/lodash.debounce-4.0.8.tgz#82d79bff30a67c4005ffd5e2515300ad9ca4d7af" + integrity sha1-gteb/zCmfEAF/9XiUVMArZyk168= + lodash.get@^4.4.2: version "4.4.2" resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" @@ -10542,6 +10566,13 @@ nanomatch@^1.2.9: snapdragon "^0.8.1" to-regex "^3.0.1" +native-url@^0.2.6: + version "0.2.6" + resolved "https://registry.yarnpkg.com/native-url/-/native-url-0.2.6.tgz#ca1258f5ace169c716ff44eccbddb674e10399ae" + integrity sha512-k4bDC87WtgrdD362gZz6zoiXQrl40kYlBmpfmSjwRO1VU0V5ccwJTlxuE72F6m3V0vc1xOf6n3UCP9QyerRqmA== + dependencies: + querystring "^0.2.0" + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -12605,7 +12636,7 @@ querystring-es3@^0.2.0: resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= -querystring@0.2.0: +querystring@0.2.0, querystring@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= @@ -12751,6 +12782,11 @@ react-is@^16.12.0, react-is@^16.7.0, react-is@^16.8.0, react-is@^16.8.1, react-i resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== +react-refresh@^0.8.3: + version "0.8.3" + resolved "https://registry.yarnpkg.com/react-refresh/-/react-refresh-0.8.3.tgz#721d4657672d400c5e3c75d063c4a85fb2d5d68f" + integrity sha512-X8jZHc7nCMjaCqoU+V2I0cOhNW+QMBwSUkeXnTi8IPe6zaRWfn60ZzvFDZqWPfmSJfjub7dDW1SP0jaHWLu/hg== + react-transition-group@^4.4.0: version "4.4.1" resolved "https://registry.yarnpkg.com/react-transition-group/-/react-transition-group-4.4.1.tgz#63868f9325a38ea5ee9535d828327f85773345c9" @@ -14100,6 +14136,11 @@ stack-utils@^2.0.2: dependencies: escape-string-regexp "^2.0.0" +stackframe@^1.1.1: + version "1.2.0" + resolved "https://registry.yarnpkg.com/stackframe/-/stackframe-1.2.0.tgz#52429492d63c62eb989804c11552e3d22e779303" + integrity sha512-GrdeshiRmS1YLMYgzF16olf2jJ/IzxXY9lhKOskuVziubpTYcYqyOwYeJKzQkwy7uN0fYSsbsC4RQaXf9LCrYA== + state-toggle@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.3.tgz#e123b16a88e143139b09c6852221bc9815917dfe"