diff --git a/.babelrc b/.babelrc index cfedf764ce..a17f10849f 100644 --- a/.babelrc +++ b/.babelrc @@ -9,7 +9,8 @@ // obeys the spec more, but we get a bundle that's 8kB larger. That was the // default in babel v6. ["@babel/plugin-proposal-class-properties", { loose: true }], - ["@babel/plugin-proposal-object-rest-spread", { useBuiltIns: true }] + ["@babel/plugin-proposal-object-rest-spread", { useBuiltIns: true }], + "syntax-dynamic-import" ], env: { test: { @@ -20,8 +21,9 @@ ], plugins: [ ["@babel/plugin-proposal-class-properties", { loose: true }], - ["@babel/plugin-proposal-object-rest-spread", { useBuiltIns: true }] - ] + ["@babel/plugin-proposal-object-rest-spread", { useBuiltIns: true }], + "dynamic-import-node" + ], } } } diff --git a/__mocks__/gecko-profiler-demangle.js b/__mocks__/gecko-profiler-demangle.js new file mode 100644 index 0000000000..c6aaf0d2de --- /dev/null +++ b/__mocks__/gecko-profiler-demangle.js @@ -0,0 +1,21 @@ +// This module replaces the wasm-pack generated module 'gecko-profiler-demangle' +// in our tests. +// The reason for this replacement is the fact that wasm-pack (or rather, +// wasm-bindgen), when targeting the browser + webpack, generates an ES6 module +// that node cannot deal with. Most importantly, it uses the syntax +// "import * as wasm from './gecko_profiler_demangle_bg';" in order to load +// the wasm module, which is currently only supported by webpack. +// The long-term path to make this work correctly is to wait for node to +// support ES6 modules (and WASM as ES6 modules) natively [1]. It's possible +// that in the medium term, wasm-bindgen will get support for outputting JS +// files which work in both webpack and in node natively [2]. +// [1] https://medium.com/@giltayar/native-es-modules-in-nodejs-status-and-future-directions-part-i-ee5ea3001f71 +// [2] https://github.com/rustwasm/wasm-bindgen/issues/233 + +// @flow + +// There's only one exported function. +// Do the simplest thing possible: no demangling. +export function demangle_any(s: string): string { + return s; +} diff --git a/package.json b/package.json index 67fec176bf..8bb35739dc 100644 --- a/package.json +++ b/package.json @@ -39,16 +39,20 @@ "dependencies": { "array-move": "^1.0.0", "array-range": "^1.0.1", + "babel-plugin-dynamic-import-node": "^2.0.0", + "babel-plugin-syntax-dynamic-import": "^6.18.0", + "babel-runtime": "^6.26.0", "bisection": "0.0.3", "clamp": "^1.0.1", "classnames": "^2.2.5", "common-tags": "^1.7.2", "copy-to-clipboard": "^3.0.8", "escape-string-regexp": "^1.0.5", + "gecko-profiler-demangle": "^0.1.0", "jszip": "^3.1.5", "memoize-immutable": "^3.0.0", "mixedtuplemap": "^1.0.0", - "offline-plugin": "^5.0.5", + "@mstange/offline-plugin": "^5.0.6", "photon-colors": "2.0.1", "prop-types": "^15.6.0", "query-string": "^5.1.0", diff --git a/src/index.js b/src/index.js index f13737ef8f..7d772b78a0 100644 --- a/src/index.js +++ b/src/index.js @@ -27,7 +27,10 @@ if (process.env.NODE_ENV === 'development') { } if (process.env.NODE_ENV === 'production') { - const runtime = require('offline-plugin/runtime'); + // We use '@mstange/offline-plugin/runtime' here instead of + // 'offline-plugin/runtime' because the fork contains the fix from + // https://github.com/NekR/offline-plugin/pull/410 + const runtime = require('@mstange/offline-plugin/runtime'); runtime.install({ onUpdateReady: () => { runtime.applyUpdate(); diff --git a/src/profile-logic/symbol-store.js b/src/profile-logic/symbol-store.js index 153c06c261..fbae9d3483 100644 --- a/src/profile-logic/symbol-store.js +++ b/src/profile-logic/symbol-store.js @@ -7,6 +7,8 @@ import SymbolStoreDB from './symbol-store-db'; import { SymbolsNotFoundError } from './errors'; import bisection from 'bisection'; +const demangleModulePromise = import('gecko-profiler-demangle'); + import type { RequestedLib } from '../types/actions'; import type { SymbolTableAsTuple } from './symbol-store-db'; @@ -117,7 +119,8 @@ export class SymbolStore { // This format is documented at the SymbolTableAsTuple flow type definition. _readSymbolsFromSymbolTable( addresses: Set, - symbolTable: SymbolTableAsTuple + symbolTable: SymbolTableAsTuple, + demangleCallback: string => string ): Map { const [symbolTableAddrs, symbolTableIndex, symbolTableBuffer] = symbolTable; const addressArray = Uint32Array.from(addresses); @@ -154,7 +157,9 @@ export class SymbolStore { const startOffset = symbolTableIndex[symbolIndex]; const endOffset = symbolTableIndex[symbolIndex + 1]; const subarray = symbolTableBuffer.subarray(startOffset, endOffset); - currentSymbol = decoder.decode(subarray); + // C++ or rust symbols in the symbol table may have mangled names. + // Demangle them here. + currentSymbol = demangleCallback(decoder.decode(subarray)); currentSymbolIndex = symbolIndex; } results.set(address, { @@ -272,10 +277,16 @@ export class SymbolStore { // symbolication for the libraries for which we found symbol tables in the // database. This is delayed until after the request has been kicked off // because it can take some time. + // We also need a demangling function for this, which is in an async module. + const demangleCallback = (await demangleModulePromise).demangle_any; for (const { request, symbolTable } of requestsForCachedLibs) { successCb( request, - this._readSymbolsFromSymbolTable(request.addresses, symbolTable) + this._readSymbolsFromSymbolTable( + request.addresses, + symbolTable, + demangleCallback + ) ); } @@ -316,7 +327,11 @@ export class SymbolStore { // Did not throw, option 3 was successful! successCb( request, - this._readSymbolsFromSymbolTable(addresses, symbolTable) + this._readSymbolsFromSymbolTable( + addresses, + symbolTable, + demangleCallback + ) ); // Store the symbol table in the database. diff --git a/src/types/libdef/npm/@mstange/offline-plugin_vx.x.x.js b/src/types/libdef/npm/@mstange/offline-plugin_vx.x.x.js new file mode 100644 index 0000000000..ee948990b1 --- /dev/null +++ b/src/types/libdef/npm/@mstange/offline-plugin_vx.x.x.js @@ -0,0 +1,137 @@ +// flow-typed signature: f84c93c5335ad9c36684cc95ca54b099 +// flow-typed version: <>/@mstange/offline-plugin_v^5.0.6/flow_v0.70.0 + +/** + * This is an autogenerated libdef stub for: + * + * '@mstange/offline-plugin' + * + * Fill this stub out by replacing all the `any` types. + * + * Once filled out, we encourage you to share your work with the + * community by sending a pull request to: + * https://github.com/flowtype/flow-typed + */ + +declare module '@mstange/offline-plugin' { + declare module.exports: any; +} + +/** + * We include stubs for each file inside this npm package in case you need to + * require those files directly. Feel free to delete any files that aren't + * needed. + */ +declare module '@mstange/offline-plugin/lib/app-cache' { + declare module.exports: any; +} + +declare module '@mstange/offline-plugin/lib/default-options' { + declare module.exports: any; +} + +declare module '@mstange/offline-plugin/lib/index' { + declare module.exports: any; +} + +declare module '@mstange/offline-plugin/lib/loaders/fonts-css' { + declare module.exports: any; +} + +declare module '@mstange/offline-plugin/lib/loaders/index' { + declare module.exports: any; +} + +declare module '@mstange/offline-plugin/lib/misc/async-waituntil' { + declare module.exports: any; +} + +declare module '@mstange/offline-plugin/lib/misc/get-uglify-plugin' { + declare module.exports: any; +} + +declare module '@mstange/offline-plugin/lib/misc/runtime-loader' { + declare module.exports: any; +} + +declare module '@mstange/offline-plugin/lib/misc/sw-loader' { + declare module.exports: any; +} + +declare module '@mstange/offline-plugin/lib/misc/sw-polyfill' { + declare module.exports: any; +} + +declare module '@mstange/offline-plugin/lib/misc/sw-template' { + declare module.exports: any; +} + +declare module '@mstange/offline-plugin/lib/misc/utils' { + declare module.exports: any; +} + +declare module '@mstange/offline-plugin/lib/service-worker' { + declare module.exports: any; +} + +declare module '@mstange/offline-plugin/runtime' { + declare module.exports: any; +} + +declare module '@mstange/offline-plugin/tpls/empty-entry' { + declare module.exports: any; +} + +declare module '@mstange/offline-plugin/tpls/runtime-template' { + declare module.exports: any; +} + +// Filename aliases +declare module '@mstange/offline-plugin/lib/app-cache.js' { + declare module.exports: $Exports<'@mstange/offline-plugin/lib/app-cache'>; +} +declare module '@mstange/offline-plugin/lib/default-options.js' { + declare module.exports: $Exports<'@mstange/offline-plugin/lib/default-options'>; +} +declare module '@mstange/offline-plugin/lib/index.js' { + declare module.exports: $Exports<'@mstange/offline-plugin/lib/index'>; +} +declare module '@mstange/offline-plugin/lib/loaders/fonts-css.js' { + declare module.exports: $Exports<'@mstange/offline-plugin/lib/loaders/fonts-css'>; +} +declare module '@mstange/offline-plugin/lib/loaders/index.js' { + declare module.exports: $Exports<'@mstange/offline-plugin/lib/loaders/index'>; +} +declare module '@mstange/offline-plugin/lib/misc/async-waituntil.js' { + declare module.exports: $Exports<'@mstange/offline-plugin/lib/misc/async-waituntil'>; +} +declare module '@mstange/offline-plugin/lib/misc/get-uglify-plugin.js' { + declare module.exports: $Exports<'@mstange/offline-plugin/lib/misc/get-uglify-plugin'>; +} +declare module '@mstange/offline-plugin/lib/misc/runtime-loader.js' { + declare module.exports: $Exports<'@mstange/offline-plugin/lib/misc/runtime-loader'>; +} +declare module '@mstange/offline-plugin/lib/misc/sw-loader.js' { + declare module.exports: $Exports<'@mstange/offline-plugin/lib/misc/sw-loader'>; +} +declare module '@mstange/offline-plugin/lib/misc/sw-polyfill.js' { + declare module.exports: $Exports<'@mstange/offline-plugin/lib/misc/sw-polyfill'>; +} +declare module '@mstange/offline-plugin/lib/misc/sw-template.js' { + declare module.exports: $Exports<'@mstange/offline-plugin/lib/misc/sw-template'>; +} +declare module '@mstange/offline-plugin/lib/misc/utils.js' { + declare module.exports: $Exports<'@mstange/offline-plugin/lib/misc/utils'>; +} +declare module '@mstange/offline-plugin/lib/service-worker.js' { + declare module.exports: $Exports<'@mstange/offline-plugin/lib/service-worker'>; +} +declare module '@mstange/offline-plugin/runtime.js' { + declare module.exports: $Exports<'@mstange/offline-plugin/runtime'>; +} +declare module '@mstange/offline-plugin/tpls/empty-entry.js' { + declare module.exports: $Exports<'@mstange/offline-plugin/tpls/empty-entry'>; +} +declare module '@mstange/offline-plugin/tpls/runtime-template.js' { + declare module.exports: $Exports<'@mstange/offline-plugin/tpls/runtime-template'>; +} diff --git a/src/types/libdef/npm/gecko-profiler-demangle_vx.x.x.js b/src/types/libdef/npm/gecko-profiler-demangle_vx.x.x.js new file mode 100644 index 0000000000..641e62c0d2 --- /dev/null +++ b/src/types/libdef/npm/gecko-profiler-demangle_vx.x.x.js @@ -0,0 +1,32 @@ +// flow-typed signature: e6f43a673a1ad489aea31817e5e11e45 +// flow-typed version: <>/gecko-profiler-demangle_v^0.1.0/flow_v0.70.0 + +/** + * This is an autogenerated libdef stub for: + * + * 'gecko-profiler-demangle' + * + * Fill this stub out by replacing all the `any` types. + * + * Once filled out, we encourage you to share your work with the + * community by sending a pull request to: + * https://github.com/flowtype/flow-typed + */ + +declare module 'gecko-profiler-demangle' { + declare module.exports: any; +} + +/** + * We include stubs for each file inside this npm package in case you need to + * require those files directly. Feel free to delete any files that aren't + * needed. + */ +declare module 'gecko-profiler-demangle/gecko_profiler_demangle' { + declare module.exports: any; +} + +// Filename aliases +declare module 'gecko-profiler-demangle/gecko_profiler_demangle.js' { + declare module.exports: $Exports<'gecko-profiler-demangle/gecko_profiler_demangle'>; +} diff --git a/webpack.config.js b/webpack.config.js index 39d213758b..de6005f115 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -2,7 +2,7 @@ const path = require('path'); const webpack = require('webpack'); const HtmlWebpackPlugin = require('html-webpack-plugin'); -const OfflinePlugin = require('offline-plugin'); +const OfflinePlugin = require('@mstange/offline-plugin'); const CopyWebpackPlugin = require('copy-webpack-plugin'); const includes = [path.join(__dirname, 'src'), path.join(__dirname, 'res')]; @@ -18,7 +18,7 @@ const config = { 'redux-devtools': path.join(__dirname, '..', '..', 'src'), react: path.join(__dirname, 'node_modules', 'react'), }, - extensions: ['.js'], + extensions: ['.js', '.wasm'], }, devtool: 'source-map', module: { @@ -79,6 +79,10 @@ const config = { chunkFilename: '[id].[hash].bundle.js', publicPath: '/', }, + optimization: { + // Workaround for https://github.com/webpack/webpack/issues/7760 + usedExports: false, + }, }; if (process.env.NODE_ENV === 'development') { diff --git a/yarn.lock b/yarn.lock index ac3c524817..4223bd5b13 100644 --- a/yarn.lock +++ b/yarn.lock @@ -647,6 +647,16 @@ version "2.2.1" resolved "https://registry.yarnpkg.com/@koa/cors/-/cors-2.2.1.tgz#c06a1c34d787e3cee79c0d4c20e8952d1b6d75c5" +"@mstange/offline-plugin@^5.0.6": + version "5.0.6" + resolved "https://registry.yarnpkg.com/@mstange/offline-plugin/-/offline-plugin-5.0.6.tgz#23d90b9e33fb5546f4b7082ba62796919e0aabb3" + dependencies: + deep-extend "^0.5.1" + ejs "^2.3.4" + loader-utils "0.2.x" + minimatch "^3.0.3" + slash "^1.0.0" + "@sinonjs/formatio@^2.0.0": version "2.0.0" resolved "https://registry.yarnpkg.com/@sinonjs/formatio/-/formatio-2.0.0.tgz#84db7e9eb5531df18a8c5e0bfb6e449e55e654b2" @@ -1349,6 +1359,13 @@ babel-messages@^6.23.0: dependencies: babel-runtime "^6.22.0" +babel-plugin-dynamic-import-node@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/babel-plugin-dynamic-import-node/-/babel-plugin-dynamic-import-node-2.0.0.tgz#d6fc3f6c5e3bdc34e49c15faca7ce069755c0a57" + dependencies: + babel-plugin-syntax-dynamic-import "^6.18.0" + object.assign "^4.1.0" + babel-plugin-istanbul@^4.1.6: version "4.1.6" resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-4.1.6.tgz#36c59b2192efce81c5b378321b74175add1c9a45" @@ -1362,6 +1379,10 @@ babel-plugin-jest-hoist@^23.2.0: version "23.2.0" resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-23.2.0.tgz#e61fae05a1ca8801aadee57a6d66b8cefaf44167" +babel-plugin-syntax-dynamic-import@^6.18.0: + version "6.18.0" + resolved "https://registry.yarnpkg.com/babel-plugin-syntax-dynamic-import/-/babel-plugin-syntax-dynamic-import-6.18.0.tgz#8d6a26229c83745a9982a441051572caa179b1da" + babel-plugin-syntax-object-rest-spread@^6.13.0, babel-plugin-syntax-object-rest-spread@^6.8.0: version "6.13.0" resolved "https://registry.yarnpkg.com/babel-plugin-syntax-object-rest-spread/-/babel-plugin-syntax-object-rest-spread-6.13.0.tgz#fd6536f2bce13836ffa3a5458c4903a597bb3bf5" @@ -4110,6 +4131,10 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" +gecko-profiler-demangle@^0.1.0: + version "0.1.0" + resolved "https://registry.yarnpkg.com/gecko-profiler-demangle/-/gecko-profiler-demangle-0.1.0.tgz#7bc08d43e3572e64a6c09c4ed6680e4bc4ce356e" + get-caller-file@^1.0.1: version "1.0.3" resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-1.0.3.tgz#f978fa4c90d1dfe7ff2d6beda2a515e713bdcf4a" @@ -6989,16 +7014,6 @@ obuf@^1.0.0, obuf@^1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/obuf/-/obuf-1.1.1.tgz#104124b6c602c6796881a042541d36db43a5264e" -offline-plugin@^5.0.5: - version "5.0.5" - resolved "https://registry.yarnpkg.com/offline-plugin/-/offline-plugin-5.0.5.tgz#e9b16c569d19899af9c923f5bc260705578ffeba" - dependencies: - deep-extend "^0.5.1" - ejs "^2.3.4" - loader-utils "0.2.x" - minimatch "^3.0.3" - slash "^1.0.0" - on-finished@^2.3.0, on-finished@~2.3.0: version "2.3.0" resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"