From 62f8b7e600837066a72165a151c34c9f20f48600 Mon Sep 17 00:00:00 2001 From: Ian Sutherland Date: Thu, 22 Nov 2018 23:42:45 -0700 Subject: [PATCH 01/12] Add support for WebWorker with worker-loader --- .../react-scripts/config/webpack.config.js | 58 +++++++++++++++++++ packages/react-scripts/package.json | 3 +- 2 files changed, 60 insertions(+), 1 deletion(-) diff --git a/packages/react-scripts/config/webpack.config.js b/packages/react-scripts/config/webpack.config.js index 80391927084..4e055236b3f 100644 --- a/packages/react-scripts/config/webpack.config.js +++ b/packages/react-scripts/config/webpack.config.js @@ -170,6 +170,7 @@ module.exports = function(webpackEnv) { // We inferred the "public path" (such as / or /my-project) from homepage. // We use "/" in development. publicPath: publicPath, + globalObject: 'this', // Point sourcemap entries to original disk location (format as URL on Windows) devtoolModuleFilenameTemplate: isEnvProduction ? info => @@ -341,6 +342,63 @@ module.exports = function(webpackEnv) { name: 'static/media/[name].[hash:8].[ext]', }, }, + // Process WebWorker JS with Babel. + // The preset includes JSX, Flow, TypeScript, and some ESnext features. + { + test: /\.worker\.(js|jsx|mjs)$/, + include: paths.appSrc, + use: [ + require.resolve('worker-loader'), + { + loader: require.resolve('babel-loader'), + options: { + customize: require.resolve( + 'babel-preset-react-app/webpack-overrides' + ), + // @remove-on-eject-begin + babelrc: false, + configFile: false, + presets: [require.resolve('babel-preset-react-app')], + // Make sure we have a unique cache identifier, erring on the + // side of caution. + // We remove this when the user ejects because the default + // is sane and uses Babel options. Instead of options, we use + // the react-scripts and babel-preset-react-app versions. + cacheIdentifier: getCacheIdentifier( + isEnvProduction + ? 'production' + : isEnvDevelopment && 'development', + [ + 'babel-plugin-named-asset-import', + 'babel-preset-react-app', + 'react-dev-utils', + 'react-scripts', + ] + ), + // @remove-on-eject-end + plugins: [ + [ + require.resolve('babel-plugin-named-asset-import'), + { + loaderMap: { + svg: { + ReactComponent: + '@svgr/webpack?-prettier,-svgo![path]', + }, + }, + }, + ], + ], + // 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. + cacheDirectory: true, + cacheCompression: isEnvProduction, + compact: isEnvProduction, + }, + }, + ], + }, // Process application JS with Babel. // The preset includes JSX, Flow, TypeScript, and some ESnext features. { diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index 1f6b8cfafec..4460a6577bf 100644 --- a/packages/react-scripts/package.json +++ b/packages/react-scripts/package.json @@ -70,7 +70,8 @@ "webpack": "4.19.1", "webpack-dev-server": "3.1.9", "webpack-manifest-plugin": "2.0.4", - "workbox-webpack-plugin": "3.6.3" + "workbox-webpack-plugin": "3.6.3", + "worker-loader": "^2.0.0" }, "devDependencies": { "react": "^16.3.2", From 24ca900334dcc52655f21c68c8c9f3438a9a3adb Mon Sep 17 00:00:00 2001 From: Ian Sutherland Date: Fri, 23 Nov 2018 00:31:21 -0700 Subject: [PATCH 02/12] Add support for writing WebWorkers in TypeScript --- packages/react-scripts/config/webpack.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-scripts/config/webpack.config.js b/packages/react-scripts/config/webpack.config.js index 4e055236b3f..ee0b6025db8 100644 --- a/packages/react-scripts/config/webpack.config.js +++ b/packages/react-scripts/config/webpack.config.js @@ -345,7 +345,7 @@ module.exports = function(webpackEnv) { // Process WebWorker JS with Babel. // The preset includes JSX, Flow, TypeScript, and some ESnext features. { - test: /\.worker\.(js|jsx|mjs)$/, + test: /\.worker\.(js|mjs|jsx|ts|tsx)$/, include: paths.appSrc, use: [ require.resolve('worker-loader'), From 69147561edfded06bda2a6a678c0664e2e0424a0 Mon Sep 17 00:00:00 2001 From: Ian Sutherland Date: Tue, 27 Nov 2018 14:21:37 -0700 Subject: [PATCH 03/12] Don't allow workers with jsx or tsx extension --- packages/react-scripts/config/webpack.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-scripts/config/webpack.config.js b/packages/react-scripts/config/webpack.config.js index ee0b6025db8..1e557c1f166 100644 --- a/packages/react-scripts/config/webpack.config.js +++ b/packages/react-scripts/config/webpack.config.js @@ -345,7 +345,7 @@ module.exports = function(webpackEnv) { // Process WebWorker JS with Babel. // The preset includes JSX, Flow, TypeScript, and some ESnext features. { - test: /\.worker\.(js|mjs|jsx|ts|tsx)$/, + test: /\.worker\.(js|mjs|ts)$/, include: paths.appSrc, use: [ require.resolve('worker-loader'), From 45707ad950b5471f9e2cb0c7bfaf8d23b6d50fb7 Mon Sep 17 00:00:00 2001 From: Matt Darveniza Date: Mon, 1 Apr 2019 16:17:24 +1100 Subject: [PATCH 04/12] Added eslint exception for worker files using 'self' --- packages/eslint-config-react-app/index.js | 74 +++++++++++++---------- 1 file changed, 42 insertions(+), 32 deletions(-) diff --git a/packages/eslint-config-react-app/index.js b/packages/eslint-config-react-app/index.js index 441b501843c..2bc6243ac9e 100644 --- a/packages/eslint-config-react-app/index.js +++ b/packages/eslint-config-react-app/index.js @@ -62,42 +62,52 @@ module.exports = { }, }, - overrides: { - files: ['**/*.ts', '**/*.tsx'], - parser: '@typescript-eslint/parser', - parserOptions: { - ecmaVersion: 2018, - sourceType: 'module', - ecmaFeatures: { - jsx: true, + overrides: [ + { + files: ['**/*.ts', '**/*.tsx'], + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaVersion: 2018, + sourceType: 'module', + ecmaFeatures: { + jsx: true, + }, + + // typescript-eslint specific options + project: tsConfigPath, + tsconfigRootDir: projectRootPath, + warnOnUnsupportedTypeScriptVersion: true, }, + plugins: ['@typescript-eslint'], + rules: { + // These ESLint rules are known to cause issues with typescript-eslint + // See https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/src/configs/recommended.json + camelcase: 'off', + indent: 'off', + 'no-array-constructor': 'off', + 'no-unused-vars': 'off', - // typescript-eslint specific options - project: tsConfigPath, - tsconfigRootDir: projectRootPath, - warnOnUnsupportedTypeScriptVersion: true, + '@typescript-eslint/no-angle-bracket-type-assertion': 'warn', + '@typescript-eslint/no-array-constructor': 'warn', + '@typescript-eslint/no-namespace': 'error', + '@typescript-eslint/no-unused-vars': [ + 'warn', + { + args: 'none', + ignoreRestSiblings: true, + }, + ], + }, }, - plugins: ['@typescript-eslint'], - rules: { - // These ESLint rules are known to cause issues with typescript-eslint - // See https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/eslint-plugin/src/configs/recommended.json - camelcase: 'off', - indent: 'off', - 'no-array-constructor': 'off', - 'no-unused-vars': 'off', - - '@typescript-eslint/no-angle-bracket-type-assertion': 'warn', - '@typescript-eslint/no-array-constructor': 'warn', - '@typescript-eslint/no-namespace': 'error', - '@typescript-eslint/no-unused-vars': [ - 'warn', - { - args: 'none', - ignoreRestSiblings: true, - }, - ], + { + files: ['**/*.worker.(js|mjs|ts)'], + rules: { + 'no-restricted-globals': ['error'].concat( + restrictedGlobals.filter(g => g !== 'self') + ), + }, }, - }, + ], // NOTE: When adding rules here, you need to make sure they are compatible with // `typescript-eslint`, as some rules such as `no-array-constructor` aren't compatible. From a671c97af023f9ce4967593daca7cb06421d8ccc Mon Sep 17 00:00:00 2001 From: Matt Darveniza Date: Mon, 1 Apr 2019 16:22:09 +1100 Subject: [PATCH 05/12] Added documentation for web workers --- docusaurus/docs/using-web-workers.md | 83 ++++++++++++++++++++++++++++ docusaurus/website/sidebars.json | 1 + 2 files changed, 84 insertions(+) create mode 100644 docusaurus/docs/using-web-workers.md diff --git a/docusaurus/docs/using-web-workers.md b/docusaurus/docs/using-web-workers.md new file mode 100644 index 00000000000..61e2bdf83d3 --- /dev/null +++ b/docusaurus/docs/using-web-workers.md @@ -0,0 +1,83 @@ +--- +id: using-web-workers +titile: Using Web Workers +--- + +[Web Workers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API/Using_web_workers) +can be used by including files with the `.worker.js` in your application. Files +with this extension make use of [`worker-loader`](https://github.com/webpack-contrib/worker-loader) +to bundle worker files which can be used by your main application. + +A sample WebWorker may look like: + +```js +// hello.worker.js + +let helloInterval; + +const sayHello = () => { + self.postMessage({ message: 'Hello' }); +}; + +self.addEventListener('message', event => { + if (event.data.run === true) { + self.postMessage({ status: 'Worker started' }); + helloInterval = setInterval(sayHello, 1000); + } + + if (event.data.run === false) { + self.postMessage({ status: 'Worker stopped' }); + clearInterval(helloInterval); + } +}); +``` + +This can subsequently be imported and used in your application as: + +```js +// index.js + +import HelloWorker from './hello.worker.js'; + +const helloWorker = new HelloWorker(); +let messageCount = 0; + +helloWorker.postMessage({ run: true }); + +helloWorker.onmessage = event => { + if (event.data.status) { + console.log('STATUS', event.data.status); + } + + if (event.data.message) { + messageCount += 1; + console.log('MESSAGE', event.data.message); + + if (messageCount >= 5) { + helloWorker.postMessage({ run: false }); + } + } +}; +``` + +## Importing modules into your workers + +Worker files can import modules just the same as the rest of your +application. These will be compiled following the same rules and features as +regular `.js` or `.ts` files. + +## Usage with TypeScript + +Workers can be written in TypeScript, however you are required to declare the +file as a worker in order for the compiler to understand that it is a worker. +This can be done by including + +```ts +/// +``` + +at the beginning of all of your `.worker.ts` files. + +You will also need to follow the [Integrating With Typescript](https://github.com/webpack-contrib/worker-loader#integrating-with-typescript) +instructions in the `worker-loader` documentation to get TypeScript to see your +worker import as the correct module and typing. diff --git a/docusaurus/website/sidebars.json b/docusaurus/website/sidebars.json index bde33240766..2811797b220 100644 --- a/docusaurus/website/sidebars.json +++ b/docusaurus/website/sidebars.json @@ -34,6 +34,7 @@ "adding-a-router", "adding-custom-environment-variables", "making-a-progressive-web-app", + "using-web-workers", "production-build" ], "Testing": ["running-tests", "debugging-tests"], From 8ba668e094987996daee0fa68858ebba8828c186 Mon Sep 17 00:00:00 2001 From: Matt Darveniza Date: Fri, 5 Apr 2019 15:48:11 +1100 Subject: [PATCH 06/12] Added constructor rule and fixed file matching --- packages/eslint-config-react-app/index.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/eslint-config-react-app/index.js b/packages/eslint-config-react-app/index.js index 2bc6243ac9e..2efe7f73a78 100644 --- a/packages/eslint-config-react-app/index.js +++ b/packages/eslint-config-react-app/index.js @@ -86,7 +86,6 @@ module.exports = { indent: 'off', 'no-array-constructor': 'off', 'no-unused-vars': 'off', - '@typescript-eslint/no-angle-bracket-type-assertion': 'warn', '@typescript-eslint/no-array-constructor': 'warn', '@typescript-eslint/no-namespace': 'error', @@ -100,11 +99,12 @@ module.exports = { }, }, { - files: ['**/*.worker.(js|mjs|ts)'], + files: ['**/*.worker.js', '**/*.worker.mjs', '**/*.worker.ts'], rules: { 'no-restricted-globals': ['error'].concat( restrictedGlobals.filter(g => g !== 'self') ), + 'no-useless-constructor': 'off', }, }, ], From 19138705501f4ce94e8e4b60034ab13b1e801736 Mon Sep 17 00:00:00 2001 From: Matt Darveniza Date: Fri, 5 Apr 2019 17:22:48 +1100 Subject: [PATCH 07/12] Updated ts worker docs --- docusaurus/docs/using-web-workers.md | 26 ++++++++++++++++++++++---- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/docusaurus/docs/using-web-workers.md b/docusaurus/docs/using-web-workers.md index 61e2bdf83d3..d037499c01c 100644 --- a/docusaurus/docs/using-web-workers.md +++ b/docusaurus/docs/using-web-workers.md @@ -70,7 +70,7 @@ regular `.js` or `.ts` files. Workers can be written in TypeScript, however you are required to declare the file as a worker in order for the compiler to understand that it is a worker. -This can be done by including +This can be done by including: ```ts /// @@ -78,6 +78,24 @@ This can be done by including at the beginning of all of your `.worker.ts` files. -You will also need to follow the [Integrating With Typescript](https://github.com/webpack-contrib/worker-loader#integrating-with-typescript) -instructions in the `worker-loader` documentation to get TypeScript to see your -worker import as the correct module and typing. +Because the interface imported is different from what is in your worker files, +you'll also need to tell TypeScript what you're expecting this interface to look +like. To achieve this, you will need to have a module declaration in each of +your worker files like so: + +```ts +// my.worker.ts +// + +// Necessary to tell typescript that this worker file is a module even though +// it may not have any explicit imports or exports +export {}; + +// Override the module declaration to tell Typescript that when imported, this +// is what the imported types will look like. +declare module './my.worker' { + export default class TestWorker extends Worker { + constructor(); + } +} +``` From 0d7c9bad5976734f0239f505af515dd3dbe7729f Mon Sep 17 00:00:00 2001 From: Matt Darveniza Date: Fri, 5 Apr 2019 17:26:02 +1100 Subject: [PATCH 08/12] Added comment explaining lint rule for workers --- packages/eslint-config-react-app/index.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/eslint-config-react-app/index.js b/packages/eslint-config-react-app/index.js index 2efe7f73a78..92925e40089 100644 --- a/packages/eslint-config-react-app/index.js +++ b/packages/eslint-config-react-app/index.js @@ -104,6 +104,7 @@ module.exports = { 'no-restricted-globals': ['error'].concat( restrictedGlobals.filter(g => g !== 'self') ), + // Necessary to allow stubbed class declartions in workers 'no-useless-constructor': 'off', }, }, From 8ff30b00671c19cc836bb1b2f44ea092a2684cd3 Mon Sep 17 00:00:00 2001 From: Ian Sutherland Date: Thu, 22 Nov 2018 23:42:45 -0700 Subject: [PATCH 09/12] Add support for WebWorker with worker-loader --- .../react-scripts/config/webpack.config.js | 58 +++++++++++++++++++ packages/react-scripts/package.json | 5 +- 2 files changed, 61 insertions(+), 2 deletions(-) diff --git a/packages/react-scripts/config/webpack.config.js b/packages/react-scripts/config/webpack.config.js index a41d60e69bc..715cd892bec 100644 --- a/packages/react-scripts/config/webpack.config.js +++ b/packages/react-scripts/config/webpack.config.js @@ -178,6 +178,7 @@ module.exports = function(webpackEnv) { // We inferred the "public path" (such as / or /my-project) from homepage. // We use "/" in development. publicPath: publicPath, + globalObject: 'this', // Point sourcemap entries to original disk location (format as URL on Windows) devtoolModuleFilenameTemplate: isEnvProduction ? info => @@ -350,6 +351,63 @@ module.exports = function(webpackEnv) { name: 'static/media/[name].[hash:8].[ext]', }, }, + // Process WebWorker JS with Babel. + // The preset includes JSX, Flow, TypeScript, and some ESnext features. + { + test: /\.worker\.(js|jsx|mjs)$/, + include: paths.appSrc, + use: [ + require.resolve('worker-loader'), + { + loader: require.resolve('babel-loader'), + options: { + customize: require.resolve( + 'babel-preset-react-app/webpack-overrides' + ), + // @remove-on-eject-begin + babelrc: false, + configFile: false, + presets: [require.resolve('babel-preset-react-app')], + // Make sure we have a unique cache identifier, erring on the + // side of caution. + // We remove this when the user ejects because the default + // is sane and uses Babel options. Instead of options, we use + // the react-scripts and babel-preset-react-app versions. + cacheIdentifier: getCacheIdentifier( + isEnvProduction + ? 'production' + : isEnvDevelopment && 'development', + [ + 'babel-plugin-named-asset-import', + 'babel-preset-react-app', + 'react-dev-utils', + 'react-scripts', + ] + ), + // @remove-on-eject-end + plugins: [ + [ + require.resolve('babel-plugin-named-asset-import'), + { + loaderMap: { + svg: { + ReactComponent: + '@svgr/webpack?-prettier,-svgo![path]', + }, + }, + }, + ], + ], + // 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. + cacheDirectory: true, + cacheCompression: isEnvProduction, + compact: isEnvProduction, + }, + }, + ], + }, // Process application JS with Babel. // The preset includes JSX, Flow, TypeScript, and some ESnext features. { diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index e8773271fef..956f75cede5 100644 --- a/packages/react-scripts/package.json +++ b/packages/react-scripts/package.json @@ -59,7 +59,7 @@ "pnp-webpack-plugin": "1.2.1", "postcss-flexbugs-fixes": "4.1.0", "postcss-loader": "3.0.0", - "postcss-normalize": "7.0.1", + "postcss-normalize": "7.0.1", "postcss-preset-env": "6.6.0", "postcss-safe-parser": "4.0.1", "react-app-polyfill": "^0.2.2", @@ -72,7 +72,8 @@ "webpack": "4.29.6", "webpack-dev-server": "3.2.1", "webpack-manifest-plugin": "2.0.4", - "workbox-webpack-plugin": "4.2.0" + "workbox-webpack-plugin": "4.2.0", + "worker-loader": "^2.0.0" }, "devDependencies": { "react": "^16.8.4", From 5ae1a34a6108f472ed6bdc99a446f9a10e45dc0d Mon Sep 17 00:00:00 2001 From: Ian Sutherland Date: Fri, 23 Nov 2018 00:31:21 -0700 Subject: [PATCH 10/12] Add support for writing WebWorkers in TypeScript --- packages/react-scripts/config/webpack.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-scripts/config/webpack.config.js b/packages/react-scripts/config/webpack.config.js index 715cd892bec..b7fbf66ec74 100644 --- a/packages/react-scripts/config/webpack.config.js +++ b/packages/react-scripts/config/webpack.config.js @@ -354,7 +354,7 @@ module.exports = function(webpackEnv) { // Process WebWorker JS with Babel. // The preset includes JSX, Flow, TypeScript, and some ESnext features. { - test: /\.worker\.(js|jsx|mjs)$/, + test: /\.worker\.(js|mjs|jsx|ts|tsx)$/, include: paths.appSrc, use: [ require.resolve('worker-loader'), From 9cc7667889a66fd7b12ffec89fd027bc513745db Mon Sep 17 00:00:00 2001 From: Ian Sutherland Date: Tue, 27 Nov 2018 14:21:37 -0700 Subject: [PATCH 11/12] Don't allow workers with jsx or tsx extension --- packages/react-scripts/config/webpack.config.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-scripts/config/webpack.config.js b/packages/react-scripts/config/webpack.config.js index b7fbf66ec74..5d0905ae580 100644 --- a/packages/react-scripts/config/webpack.config.js +++ b/packages/react-scripts/config/webpack.config.js @@ -354,7 +354,7 @@ module.exports = function(webpackEnv) { // Process WebWorker JS with Babel. // The preset includes JSX, Flow, TypeScript, and some ESnext features. { - test: /\.worker\.(js|mjs|jsx|ts|tsx)$/, + test: /\.worker\.(js|mjs|ts)$/, include: paths.appSrc, use: [ require.resolve('worker-loader'), From a5058d609606be6643b9d4ba8a3f630e02b537d8 Mon Sep 17 00:00:00 2001 From: Matt Darveniza Date: Thu, 11 Apr 2019 10:26:33 +1000 Subject: [PATCH 12/12] clarified comment --- packages/eslint-config-react-app/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/eslint-config-react-app/index.js b/packages/eslint-config-react-app/index.js index 92925e40089..b92232a3b4e 100644 --- a/packages/eslint-config-react-app/index.js +++ b/packages/eslint-config-react-app/index.js @@ -104,7 +104,7 @@ module.exports = { 'no-restricted-globals': ['error'].concat( restrictedGlobals.filter(g => g !== 'self') ), - // Necessary to allow stubbed class declartions in workers + // Necessary to allow stubbed class declartions in typescript workers 'no-useless-constructor': 'off', }, },