diff --git a/packages/react-scripts/config/jest/wasmTransform.js b/packages/react-scripts/config/jest/wasmTransform.js new file mode 100644 index 00000000000..fb20489aeaa --- /dev/null +++ b/packages/react-scripts/config/jest/wasmTransform.js @@ -0,0 +1,31 @@ +// @remove-on-eject-begin +/** + * Copyright (c) 2018-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. + */ +// @remove-on-eject-end +'use strict'; + +const path = require('path'); + +// This is a custom Jest transformer for WASM imports. +// http://facebook.github.io/jest/docs/en/webpack.html + +module.exports = { + process(src, filename) { + const assetFilename = JSON.stringify(path.basename(filename)); + + return ` + const fs = require('fs'); + const buffer = fs.readFileSync(${assetFilename}); + const module = new WebAssembly.Module(buffer); + const instance = new WebAssembly.Instance(module); + + module.exports = { + __esmodule: true, + default: instance.exports, + }`; + }, +}; diff --git a/packages/react-scripts/config/paths.js b/packages/react-scripts/config/paths.js index b719054583b..c4549cc14e2 100644 --- a/packages/react-scripts/config/paths.js +++ b/packages/react-scripts/config/paths.js @@ -58,6 +58,7 @@ const moduleFileExtensions = [ 'json', 'web.jsx', 'jsx', + 'wasm', ]; // Resolve file paths in the same order as webpack diff --git a/packages/react-scripts/config/webpack.config.js b/packages/react-scripts/config/webpack.config.js index 746884a03eb..4a558d6b1e1 100644 --- a/packages/react-scripts/config/webpack.config.js +++ b/packages/react-scripts/config/webpack.config.js @@ -506,7 +506,7 @@ module.exports = function(webpackEnv) { // its runtime that would otherwise be processed through "file" loader. // Also exclude `html` and `json` extensions so they get processed // by webpacks internal loaders. - exclude: [/\.(js|mjs|jsx|ts|tsx)$/, /\.html$/, /\.json$/], + exclude: [/\.(js|mjs|jsx|ts|tsx|wasm)$/, /\.html$/, /\.json$/], options: { name: 'static/media/[name].[hash:8].[ext]', }, diff --git a/packages/react-scripts/fixtures/kitchensink/integration/webpack.test.js b/packages/react-scripts/fixtures/kitchensink/integration/webpack.test.js index 32c9b47a48d..a08b71f8ce2 100644 --- a/packages/react-scripts/fixtures/kitchensink/integration/webpack.test.js +++ b/packages/react-scripts/fixtures/kitchensink/integration/webpack.test.js @@ -146,5 +146,11 @@ describe('Integration', () => { ); doc.defaultView.close(); }); + + it('wasm inclusion', async () => { + const doc = await initDOM('wasm-inclusion'); + + expect(doc.getElementById('wasm-inclusion').textContent).toBe('11'); + }); }); }); diff --git a/packages/react-scripts/fixtures/kitchensink/src/App.js b/packages/react-scripts/fixtures/kitchensink/src/App.js index 380a49fc639..6464e22be18 100644 --- a/packages/react-scripts/fixtures/kitchensink/src/App.js +++ b/packages/react-scripts/fixtures/kitchensink/src/App.js @@ -222,6 +222,11 @@ class App extends Component { this.setFeature(f.default) ); break; + case 'wasm-inclusion': + import('./features/webpack/WasmInclusion').then(f => + this.setFeature(f.default) + ); + break; default: throw new Error(`Missing feature "${feature}"`); } diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/WasmInclusion.js b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/WasmInclusion.js new file mode 100644 index 00000000000..f8e54d7774d --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/WasmInclusion.js @@ -0,0 +1,6 @@ +import React from 'react'; +import('./assets/add.wasm') + .then(console.log) + .catch(console.log); + +export default () => ; diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/WasmInclusion.test.js b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/WasmInclusion.test.js new file mode 100644 index 00000000000..aeb2cb59d44 --- /dev/null +++ b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/WasmInclusion.test.js @@ -0,0 +1,17 @@ +/** + * 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. + */ + +import React from 'react'; +import ReactDOM from 'react-dom'; +import WasmInclusion from './WasmInclusion'; + +describe('wasm inclusion', () => { + it('renders without crashing', () => { + const div = document.createElement('div'); + ReactDOM.render(, div); + }); +}); diff --git a/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/add.wasm b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/add.wasm new file mode 100644 index 00000000000..357f72da7a0 Binary files /dev/null and b/packages/react-scripts/fixtures/kitchensink/src/features/webpack/assets/add.wasm differ diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index 1f6b8cfafec..c27b8eb16b0 100644 --- a/packages/react-scripts/package.json +++ b/packages/react-scripts/package.json @@ -67,7 +67,7 @@ "style-loader": "0.23.0", "terser-webpack-plugin": "1.1.0", "url-loader": "1.1.1", - "webpack": "4.19.1", + "webpack": "4.23.0", "webpack-dev-server": "3.1.9", "webpack-manifest-plugin": "2.0.4", "workbox-webpack-plugin": "3.6.3" diff --git a/packages/react-scripts/scripts/utils/createJestConfig.js b/packages/react-scripts/scripts/utils/createJestConfig.js index 58c2ad48812..d01a092c6ac 100644 --- a/packages/react-scripts/scripts/utils/createJestConfig.js +++ b/packages/react-scripts/scripts/utils/createJestConfig.js @@ -52,6 +52,7 @@ module.exports = (resolve, rootDir, isEjecting) => { '^(?!.*\\.(js|jsx|ts|tsx|css|json)$)': resolve( 'config/jest/fileTransform.js' ), + '^.+\\.wasm': resolve('config/jest/wasmTransform.js'), }, transformIgnorePatterns: [ '[/\\\\]node_modules[/\\\\].+\\.(js|jsx|ts|tsx)$',