diff --git a/docusaurus/docs/adding-a-sass-stylesheet.md b/docusaurus/docs/adding-a-sass-stylesheet.md index 1ba76380e6a..1697de27541 100644 --- a/docusaurus/docs/adding-a-sass-stylesheet.md +++ b/docusaurus/docs/adding-a-sass-stylesheet.md @@ -37,6 +37,7 @@ This will allow you to do imports like To use imports relative to a path you specify, and from `node_modules` without adding the `~` prefix, you can add a [`.env` file](https://github.com/facebook/create-react-app/blob/master/docusaurus/docs/adding-custom-environment-variables.md#adding-development-environment-variables-in-env) at the project root with the variable `SASS_PATH=node_modules:src`. To specify more directories you can add them to `SASS_PATH` separated by a `:` like `path1:path2:path3`. If you set `SASS_PATH=node_modules:src`, this will allow you to do imports like + ```scss @import 'styles/colors'; // assuming a styles directory under src/, where _colors.scss partial file exists. @import 'nprogress/nprogress'; // importing a css file from the nprogress node module diff --git a/docusaurus/docs/advanced-configuration.md b/docusaurus/docs/advanced-configuration.md index 70ad7ebfb30..55ad8a8f77d 100644 --- a/docusaurus/docs/advanced-configuration.md +++ b/docusaurus/docs/advanced-configuration.md @@ -3,7 +3,7 @@ id: advanced-configuration title: Advanced Configuration --- -You can adjust various development and production settings by setting environment variables in your shell or with [.env](adding-custom-environment-variables.md#adding-development-environment-variables-in-env). +You can adjust various development and production settings by setting environment variables in your shell or with [.env](adding-custom-environment-variables.md#adding-development-environment-variables-in-env). > Note: You do not need to declare `REACT_APP_` before the below variables as you would with custom environment variables. @@ -13,7 +13,7 @@ You can adjust various development and production settings by setting environmen | HOST | βœ… Used | 🚫 Ignored | By default, the development web server binds to `localhost`. You may use this variable to specify a different host. | | PORT | βœ… Used | 🚫 Ignored | By default, the development web server will attempt to listen on port 3000 or prompt you to attempt the next available port. You may use this variable to specify a different port. | | HTTPS | βœ… Used | 🚫 Ignored | When set to `true`, Create React App will run the development server in `https` mode. | -| PUBLIC_URL | 🚫 Ignored | βœ… Used | Create React App assumes your application is hosted at the serving web server's root or a subpath as specified in [`package.json` (`homepage`)](deployment#building-for-relative-paths). Normally, Create React App ignores the hostname. You may use this variable to force assets to be referenced verbatim to the url you provide (hostname included). This may be particularly useful when using a CDN to host your application. | +| PUBLIC_URL | 🚫 Ignored | βœ… Used | Create React App assumes your application is hosted at the serving web server's root or a subpath as specified in [`package.json` (`homepage`)](deployment#building-for-relative-paths). Normally, Create React App ignores the hostname. You may use this variable to force assets to be referenced verbatim to the url you provide (hostname included). This may be particularly useful when using a CDN to host your application. | | CI | βœ… Used | βœ… Used | When set to `true`, Create React App treats warnings as failures in the build. It also makes the test runner non-watching. Most CIs set this flag by default. | | REACT_EDITOR | βœ… Used | 🚫 Ignored | When an app crashes in development, you will see an error overlay with clickable stack trace. When you click on it, Create React App will try to determine the editor you are using based on currently running processes, and open the relevant source file. You can [send a pull request to detect your editor of choice](https://github.com/facebook/create-react-app/issues/2636). Setting this environment variable overrides the automatic detection. If you do it, make sure your systems [PATH]() environment variable points to your editor’s bin folder. You can also set it to `none` to disable it completely. | | CHOKIDAR_USEPOLLING | βœ… Used | 🚫 Ignored | When set to `true`, the watcher runs in polling mode, as necessary inside a VM. Use this option if `npm start` isn't detecting changes. | diff --git a/docusaurus/docs/loading-graphql-files.md b/docusaurus/docs/loading-graphql-files.md index 423cbff3d3e..99996707d93 100644 --- a/docusaurus/docs/loading-graphql-files.md +++ b/docusaurus/docs/loading-graphql-files.md @@ -59,7 +59,7 @@ You can also use the `gql` template tag the same way you would use the non-macro ```js import { gql } from 'graphql.macro'; - + const query = gql` query User { user(id: 5) { diff --git a/docusaurus/docs/using-web-workers.md b/docusaurus/docs/using-web-workers.md new file mode 100644 index 00000000000..d037499c01c --- /dev/null +++ b/docusaurus/docs/using-web-workers.md @@ -0,0 +1,101 @@ +--- +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. + +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(); + } +} +``` diff --git a/docusaurus/website/sidebars.json b/docusaurus/website/sidebars.json index 53cbd68ffe1..994855eb33f 100644 --- a/docusaurus/website/sidebars.json +++ b/docusaurus/website/sidebars.json @@ -36,6 +36,7 @@ "adding-a-router", "adding-custom-environment-variables", "making-a-progressive-web-app", + "using-web-workers", "production-build" ], "Testing": ["running-tests", "debugging-tests"], diff --git a/packages/eslint-config-react-app/index.js b/packages/eslint-config-react-app/index.js index 4026a82f427..5d0c5140d7a 100644 --- a/packages/eslint-config-react-app/index.js +++ b/packages/eslint-config-react-app/index.js @@ -52,40 +52,51 @@ 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 - warnOnUnsupportedTypeScriptVersion: true, + // typescript-eslint specific options + 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/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', '**/*.worker.mjs', '**/*.worker.ts'], + rules: { + 'no-restricted-globals': ['error'].concat( + restrictedGlobals.filter(g => g !== 'self') + ), + // Necessary to allow stubbed class declartions in typescript workers + 'no-useless-constructor': 'off', + }, }, - }, + ], // 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. diff --git a/packages/react-scripts/config/webpack.config.js b/packages/react-scripts/config/webpack.config.js index a41d60e69bc..5d0905ae580 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|mjs|ts)$/, + 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/fixtures/kitchensink/src/App.js b/packages/react-scripts/fixtures/kitchensink/src/App.js index 547138832f3..469b573a39c 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/App.js +++ b/packages/react-scripts/fixtures/kitchensink/src/App.js @@ -68,7 +68,7 @@ class App extends Component { // This works around an issue of a duplicate hash in the href // Ex: http://localhost:3001/#array-destructuring#array-destructuring // This seems like a jsdom bug as the URL in initDom.js appears to be correct - const feature = url.slice(url.lastIndexOf("#") + 1); + const feature = url.slice(url.lastIndexOf('#') + 1); switch (feature) { case 'array-destructuring': 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", diff --git a/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js b/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js index 4e6e8c96beb..958cb984c80 100644 --- a/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js +++ b/packages/react-scripts/scripts/utils/verifyTypeScriptSetup.js @@ -18,7 +18,10 @@ const immer = require('react-dev-utils/immer').produce; const globby = require('react-dev-utils/globby').sync; function writeJson(fileName, object) { - fs.writeFileSync(fileName, JSON.stringify(object, null, 2).replace(/\n/g, os.EOL) + os.EOL); + fs.writeFileSync( + fileName, + JSON.stringify(object, null, 2).replace(/\n/g, os.EOL) + os.EOL + ); } function verifyNoTypeScript() { @@ -184,7 +187,7 @@ function verifyTypeScriptSetup() { ) ); } - + console.log(e && e.message ? `${e.message}` : ''); process.exit(1); }