From eec7c562ca9713378b67e2a983a970f85327bbbb Mon Sep 17 00:00:00 2001 From: Jack Works Date: Fri, 24 Jul 2020 18:12:27 +0800 Subject: [PATCH] feat: hmr example --- package.json | 8 ++- scripts/gulp/assets.ts | 58 +++++++++--------- scripts/gulp/build-iOS.ts | 1 - scripts/gulp/build-isolated.ts | 2 +- scripts/gulp/build-worker.ts | 14 ++--- scripts/gulp/dependencies.ts | 29 ++++++++- scripts/gulp/helper.ts | 33 ++++++++-- scripts/gulp/hmr.ts | 20 +++++++ scripts/gulp/index.ts | 6 +- scripts/gulp/paths.ts | 3 + scripts/gulp/tree-shake-loader.ts | 2 +- scripts/gulp/tsc.ts | 11 ++-- src/background-service.ts | 3 +- .../DecryptedPost/DecryptedPost.tsx | 5 +- .../DeveloperComponents/DecryptPost.tsx | 2 +- src/extension/options-page/index.tsx | 8 +-- src/utils/hmr-client.ts | 24 ++++++++ src/utils/hmr-react.tsx | 35 +++++++++++ tsconfig.json | 1 + yarn.lock | 60 +++++++++++++++++++ 20 files changed, 260 insertions(+), 65 deletions(-) create mode 100644 scripts/gulp/hmr.ts create mode 100644 src/utils/hmr-client.ts create mode 100644 src/utils/hmr-react.tsx diff --git a/package.json b/package.json index 19f8cbf62809..4e9597c5252e 100644 --- a/package.json +++ b/package.json @@ -115,6 +115,8 @@ "@types/enzyme-adapter-react-16": "^1.0.6", "@types/expect-puppeteer": "^4.4.3", "@types/gulp": "^4.0.6", + "@types/gulp-changed": "^0.0.33", + "@types/gulp-rename": "^0.0.33", "@types/gulp-zip": "^4.0.1", "@types/gun": "^0.9.2", "@types/jest": "^26.0.3", @@ -130,10 +132,12 @@ "@types/react-router-dom": "^5.1.5", "@types/react-virtualized-auto-sizer": "^1.0.0", "@types/react-window": "^1.8.2", + "@types/rimraf": "^3.0.0", "@types/tiny-secp256k1": "^1.0.0", "@types/use-subscription": "^1.0.0", "@types/uuid": "^8.0.0", "@types/webpack": "^4.41.18", + "@types/ws": "^7.2.6", "@typescript-eslint/eslint-plugin": "^3.4.0", "@typescript-eslint/parser": "^3.5.0", "babel-loader": "^8.1.0", @@ -150,6 +154,7 @@ "expect-puppeteer": "^4.4.0", "fake-indexeddb": "^3.0.2", "gulp": "^4.0.2", + "gulp-changed": "^4.0.2", "gulp-multi-process": "^1.4.0", "gulp-rename": "^2.0.0", "gulp-zip": "^5.0.2", @@ -179,7 +184,8 @@ "typescript": "^3.9.7", "web-ext": "^4.3.0", "web-ext-types": "^3.1.0", - "webpack": "^4.43.0" + "webpack": "^4.43.0", + "ws": "^7.3.1" }, "optionalDependencies": { "expect-puppeteer": "^4.4.0", diff --git a/scripts/gulp/assets.ts b/scripts/gulp/assets.ts index 57102c756c67..375348840655 100644 --- a/scripts/gulp/assets.ts +++ b/scripts/gulp/assets.ts @@ -1,48 +1,45 @@ -import { src, dest, watch, lastRun } from 'gulp' +import { src, dest, watch } from 'gulp' import * as modifier from './manifest.overrides' -import { createTask, modifyFile, named } from './helper' +import { copyOnChange, createTask, modifyFile, named } from './helper' import { assetsPath, output, manifestPath, srcPath } from './paths' import { buildTarget, getEnvironment } from './env' -// @ts-ignore import rename from 'gulp-rename' +import changed from 'gulp-changed' -const sourceAssetsDesc = - 'Copy all assets allocated in src/* to extension/esm/* to enable them to be used by import.meta' -export function srcAssets() { - return src( +export const [srcAssets, watchSrcAssets] = copyOnChange({ + name: 'src-assets', + desc: 'Copy all assets to the extension folder', + from: [ [ srcPath.files, `!${srcPath.relative('./**/*.ts')}`, `!${srcPath.relative('./**/*.tsx')}`, `!${srcPath.relative('./**/*.js')}`, ], - { - since: lastRun(srcAssets), - }, - ).pipe(dest(output.esmBuildClone.folder)) -} -named('src-assets', sourceAssetsDesc + ' (build)', srcAssets) -export const watchSrcAssets = named('watch-src-assets', sourceAssetsDesc + ' (watch)', () => - watch(srcPath.folder, { ignoreInitial: true, ignored: ['*.ts', '*.tsx'] }, srcAssets), -) + ], + to: output.esmBuildClone.folder, + watch: [srcPath.folder, { ignored: ['*.ts', '*.tsx'] }], +}) -export function assets() { - return src(assetsPath.files, { since: lastRun(assets) }).pipe(dest(output.extension.folder)) -} -named(assets.name, 'Copy all assets to the extension folder (build)', assets) -export const watchAssets = named('watch-assets', 'Copy all assets to the extension folder (watch)', () => - watch(assetsPath.folder, { ignoreInitial: false }, assets), -) +export const [assets, watchAssets] = copyOnChange({ + name: 'assets', + desc: 'Copy all assets to the extension folder', + from: [assetsPath.files], + to: output.extension.folder, + watch: [assetsPath.folder], +}) const modify = (watch: boolean) => (x: string): string => { const obj = JSON.parse(x) if (watch) modifier.development(obj) + else modifier.production(obj) modifier[buildTarget](obj) return JSON.stringify(obj, void 0, 4) } export function manifest() { return src(manifestPath.file) .pipe(modifyFile(modify(false))) + .pipe(changed(output.extension.folder)) .pipe(dest(output.extension.folder)) } named(manifest.name, 'Generate the extension manifest based on the build target (build)', manifest) @@ -50,14 +47,18 @@ export const watchManifest = named( 'watch-manifest', 'Generate the extension manifest based on the build target (watch)', () => - watch(manifestPath.file, { ignoreInitial: false }, function watch_manifest_inner() { - return src(manifestPath.file) - .pipe(modifyFile(modify(false))) - .pipe(dest(output.extension.folder)) + watch(manifestPath.file, { ignoreInitial: false }, function manifest() { + return ( + src(manifestPath.file) + // Notify the true. this is different than the fn manifest above. + .pipe(modifyFile(modify(true))) + .pipe(changed(output.extension.folder)) + .pipe(dest(output.extension.folder)) + ) }), ) -export const { build: environmentFile, watch: watchEnvironmentFile } = createTask( +export const [environmentFile, watchEnvironmentFile] = createTask( 'environment-file', 'Create a env.js in the output folder for environment variables', (mode) => () => @@ -69,5 +70,6 @@ globalThis.process.env = ${JSON.stringify(getEnvironment(mode))};`, ), ) .pipe(rename('env.js')) + .pipe(changed(output.extension.folder)) .pipe(dest(output.extension.folder)), ) diff --git a/scripts/gulp/build-iOS.ts b/scripts/gulp/build-iOS.ts index b4b37956976b..f8c879ad1172 100644 --- a/scripts/gulp/build-iOS.ts +++ b/scripts/gulp/build-iOS.ts @@ -3,7 +3,6 @@ import { buildArchitecture, buildTarget } from './env' import { output } from './paths' import { gulpPrebuilt } from '@dimensiondev/webextension-shim/dist/bin/prebuilt-lib' import { named } from './helper' -// @ts-ignore import rimraf from 'rimraf' import { promisify } from 'util' export function prebuilt_iOS(done: any) { diff --git a/scripts/gulp/build-isolated.ts b/scripts/gulp/build-isolated.ts index d1967c209c88..84496ab51646 100644 --- a/scripts/gulp/build-isolated.ts +++ b/scripts/gulp/build-isolated.ts @@ -1,6 +1,6 @@ import { buildWebpackTask, getWebpackConfig } from './helper' import { output, IsolatedEntries } from './paths' -export const { build: isolatedBuild, watch: isolatedWatch } = buildWebpackTask( +export const [isolatedBuild, isolatedWatch] = buildWebpackTask( 'isolated', 'Build isolated entries (injected scripts) by Webpack', (mode) => { diff --git a/scripts/gulp/build-worker.ts b/scripts/gulp/build-worker.ts index a31dd07be9c8..dfc99ef4d45a 100644 --- a/scripts/gulp/build-worker.ts +++ b/scripts/gulp/build-worker.ts @@ -7,12 +7,8 @@ */ import { buildWebpackTask, getWebpackConfig } from './helper' import { output, WorkerEntries } from './paths' -export const { build: workerBuild, watch: workerWatch } = buildWebpackTask( - 'workers', - 'Build Web Workers by Webpack', - (mode) => { - const conf = getWebpackConfig(mode, WorkerEntries, output.workers.folder) - conf.target = 'webworker' - return conf - }, -) +export const [workerBuild, workerWatch] = buildWebpackTask('workers', 'Build Web Workers by Webpack', (mode) => { + const conf = getWebpackConfig(mode, WorkerEntries, output.workers.folder) + conf.target = 'webworker' + return conf +}) diff --git a/scripts/gulp/dependencies.ts b/scripts/gulp/dependencies.ts index 326ecf69b980..111d77aca85c 100644 --- a/scripts/gulp/dependencies.ts +++ b/scripts/gulp/dependencies.ts @@ -1,14 +1,37 @@ import { readFileSync } from 'fs' import HtmlWebpackPlugin from 'html-webpack-plugin' import type { Configuration } from 'webpack' -import { buildWebpackTask, getWebpackConfig } from './helper' +import { buildWebpackTask, copyOnChange, getWebpackConfig } from './helper' import { assetsPath, entries, output } from './paths' -export const { watch: dependenciesWatch, build: dependenciesBuild } = buildWebpackTask( +const runtimeOut = output.libraries.relativeFolder('./bundle/') +const [, copyWebpackOut1] = copyOnChange({ + name: 'copy-webpack-output', + desc: 'Copy webpack output', + from: [output.webpackDependenciesJS.files], + to: output.librariesBundle.folder, + watch: [output.webpackDependenciesJS.folder], +}) +const [, copyWebpackOut2] = copyOnChange({ + name: 'copy-webpack-output', + desc: 'Copy webpack output', + from: [output.webpackDependenciesHTML.relative('./*.html')], + to: output.extension.folder, + watch: [output.webpackDependenciesHTML.folder], +}) +export const [dependenciesBuild, dependenciesWatch] = buildWebpackTask( 'dependencies', 'Build all node style dependencies by Webpack', (mode) => { - const obj = getWebpackConfig(mode, entries, output.libraries.relative('./bundle/')) + const obj = getWebpackConfig( + mode, + entries, + mode === 'development' ? output.webpackDependenciesJS.folder : runtimeOut.folder, + ) + if (mode === 'development') { + copyWebpackOut1(() => {}) + copyWebpackOut2(() => {}) + } obj.output!.publicPath = output.libraries.relativeFromRuntimeExtensionRoot('./bundle/') // replace ts-loader obj.module!.rules[2] = { diff --git a/scripts/gulp/helper.ts b/scripts/gulp/helper.ts index 4b77c0cc426e..1bc0fb82d89a 100644 --- a/scripts/gulp/helper.ts +++ b/scripts/gulp/helper.ts @@ -1,10 +1,11 @@ import { promisify } from 'util' import type { Configuration } from 'webpack' import webpack from 'webpack' -import type { TaskFunction } from 'gulp' +import { dest, lastRun, src, TaskFunction, watch } from 'gulp' import ts from 'typescript' import { getEnvironment } from './env' import { Readable, Transform } from 'stream' +import changed from 'gulp-changed' export function modifyFile(fn: (x: string) => string) { const stream = new Transform({ @@ -90,13 +91,13 @@ export function buildWebpackTask(name: string, desc: string, config: (mode: Conf } watch.displayName = `watch-${name}` watch.description = `${desc} (watch)` - return { watch, build } + return [build, watch] as const } export function createTask(name: string, desc: string, f: (mode: Configuration['mode']) => TaskFunction) { - return { - watch: named(`watch-${name}`, `${desc} (watch)`, f('development')), - build: named(name, `${desc} (build)`, f('production')), - } + return [ + named(name, `${desc} (build)`, f('production')), + named(`watch-${name}`, `${desc} (watch)`, f('development')), + ] as const } export function named(displayName: string, desc: string, f: TaskFunction) { f.displayName = displayName @@ -111,3 +112,23 @@ export function toSystem(x: string) { }, }).outputText } +export function copyOnChange(opts: { + name: string + desc: string + from: Parameters + to: string + watch: Parameters + transform?: (s: NodeJS.ReadWriteStream) => NodeJS.ReadWriteStream +}) { + const { desc, name, from, to, watch: watchProps, transform } = opts + function copy() { + let s = src(from[0], { since: lastRun(copy), ...from[1] }) + if (transform) s = transform(s) + return s.pipe(changed(to)).pipe(dest(to)) + } + named(name, desc + ' (build)', copy) + const watchCopy = named('watch-' + name, desc + ' (watch)', () => + watch(watchProps[0], { ignoreInitial: false, ...watchProps[1] }, copy), + ) + return [copy, watchCopy] as const +} diff --git a/scripts/gulp/hmr.ts b/scripts/gulp/hmr.ts new file mode 100644 index 000000000000..796653fac15d --- /dev/null +++ b/scripts/gulp/hmr.ts @@ -0,0 +1,20 @@ +import WebSocket, { Server } from 'ws' +import { watch } from 'gulp' +import { output } from './paths' +import { posix } from 'path' +import { pathToFileURL } from 'url' +export function hmrServer() { + const server = new Server({ port: 7687 }) + const clients = new Set() + server.addListener('connection', (client) => { + clients.add(client) + client.addListener('close', () => clients.delete(client)) + }) + const watcher = watch(output.extension.folder) + watcher.addListener('change', (fileName) => { + const url = pathToFileURL(fileName).href + const r = posix.relative(pathToFileURL(output.extension.folder).href, url) + console.log(r, 'changed') + for (const each of clients) each.send(r) + }) +} diff --git a/scripts/gulp/index.ts b/scripts/gulp/index.ts index 5ad964304da6..44acadaf23fe 100644 --- a/scripts/gulp/index.ts +++ b/scripts/gulp/index.ts @@ -21,6 +21,8 @@ import { workerBuild, workerWatch } from './build-worker' import { isolatedBuild, isolatedWatch } from './build-isolated' import { prebuilt_iOS } from './build-iOS' import { buildTarget } from './env' +import { hmrServer } from './hmr' +import rimraf from 'rimraf' function parallelProcessWatch(done: any) { return gulpMultiProcess( @@ -53,6 +55,7 @@ export const watch = named( isolatedWatch, watchCopyESMOut, parallelProcessWatch, + hmrServer, ), ), ) @@ -95,7 +98,7 @@ function parallelProcessBuild(done: any) { ) } export function clean(cb: any) { - require('rimraf')(output.extension.folder, cb) + rimraf(output.extension.folder, cb) } named(clean.name!, 'Clean previous extension build', clean) @@ -109,3 +112,4 @@ export * from './libraries' export * from './build-worker' export * from './build-iOS' export * from './build-ci' +export * from './hmr' diff --git a/scripts/gulp/paths.ts b/scripts/gulp/paths.ts index 8acec677319b..1c1a52542cd1 100644 --- a/scripts/gulp/paths.ts +++ b/scripts/gulp/paths.ts @@ -31,9 +31,12 @@ export const output = { temp: folder('../../temp/'), extension: folder('../../temp/extension/'), esmBuildOriginal: folder('../../temp/esm/'), + webpackDependenciesHTML: folder('../../temp/webpack/'), + webpackDependenciesJS: folder('../../temp/webpack/libraries/bundle/'), esmBuildClone: folder('../../temp/extension/esm/'), systemBuild: folder('../../temp/extension/system/'), libraries: folder('../../temp/extension/libraries/'), + librariesBundle: folder('../../temp/extension/libraries/bundle/'), polyfills: folder('../../temp/extension/polyfills/'), loaders: folder('../../temp/extension/loaders/'), isolated: folder('../../temp/extension/isolated/'), diff --git a/scripts/gulp/tree-shake-loader.ts b/scripts/gulp/tree-shake-loader.ts index e72145396d56..da91e841cd42 100644 --- a/scripts/gulp/tree-shake-loader.ts +++ b/scripts/gulp/tree-shake-loader.ts @@ -91,7 +91,7 @@ function createRegisterFromImportCall(node: CallExpression) { if (!isImportCall(node)) return createEmptyStatement() const arg0 = node.arguments[0] if (isStringLiteral(arg0) && arg0.text.startsWith('.')) return createImportDeclaration(void 0, void 0, void 0, arg0) - return createExpressionStatement(createRegisterCall(arg0, node)) + return createEmptyStatement() } /** * export { x as y } from 'z' diff --git a/scripts/gulp/tsc.ts b/scripts/gulp/tsc.ts index f2a850bbddee..a45bc4772b99 100644 --- a/scripts/gulp/tsc.ts +++ b/scripts/gulp/tsc.ts @@ -4,15 +4,16 @@ import { output, srcPath, tsconfigESMPath } from './paths' import { createTask, modifyFile, named, toSystem } from './helper' import { join } from 'path' import { buildTarget } from './env' +import changed from 'gulp-changed' const typescriptCLI = join(require.resolve('ttypescript'), '../tsc.js') -export const { build: tscESModuleBuild, watch: tscESModuleWatch } = createTask( +export const [tscESModuleBuild, tscESModuleWatch] = createTask( 'esm', 'Build all TypeScript into browser ES Module', (mode) => () => spawn( 'node', - [typescriptCLI, '-b', '--preserveWatchOutput', tsconfigESMPath.file, mode === 'development' ? ' -w' : ''], + [typescriptCLI, '--preserveWatchOutput', '-p', tsconfigESMPath.file, mode === 'development' ? ' -w' : ''], { stdio: 'inherit', cwd: srcPath.relative('../'), @@ -27,6 +28,7 @@ export const tscSystemBuild = named( if (buildTarget !== 'firefox') return done() return src(output.esmBuildOriginal.js, { since: lastRun(tscSystemBuild) }) .pipe(modifyFile((x) => toSystem(x).replace('ttsclib.js', 'ttsclib-system.js'))) + .pipe(changed(output.systemBuild.folder)) .pipe(dest(output.systemBuild.folder)) }, ) @@ -35,9 +37,10 @@ export const tscSystemWatch = named( 'Build all TypeScript into SystemJS format for Firefox (watch)', () => watch(output.esmBuildOriginal.folder, { ignoreInitial: false }, tscSystemBuild), ) -// We have to do the copy, cause https://bugzilla.mozilla.org/show_bug.cgi?id=1654463 export function copyESMOut() { - return src(output.esmBuildOriginal.js, { since: lastRun(copyESMOut) }).pipe(dest(output.esmBuildClone.folder)) + return src(output.esmBuildOriginal.js, { since: lastRun(copyESMOut) }) + .pipe(changed(output.esmBuildClone.folder)) + .pipe(dest(output.esmBuildClone.folder)) } named('copy-esm-out', 'Copy files from tsc output (build)', copyESMOut) export const watchCopyESMOut = named('watch-copy-esm-out', 'Copy files from tsc output (watch)', () => diff --git a/src/background-service.ts b/src/background-service.ts index 3f3c9782616a..6853e92632ae 100644 --- a/src/background-service.ts +++ b/src/background-service.ts @@ -5,6 +5,7 @@ import './_background_loader.1' import './_background_loader.2' import './extension/service' import './provider.worker' +import './utils/hmr-client' if (process.env.NODE_ENV === 'development') import('./network/matrix/instance') if (process.env.NODE_ENV === 'development') import('./protocols/wallet-provider/metamask-provider') @@ -78,7 +79,7 @@ if (GetContext() === 'background') { if (HasNoBrowserTabUI) { exclusiveTasks('https://m.facebook.com/', { important: true }) } - exclusiveTasks(getWelcomePageURL({}), { important: true }) + // exclusiveTasks(getWelcomePageURL({}), { important: true }) }) } async function getContentScripts() { diff --git a/src/components/InjectedComponents/DecryptedPost/DecryptedPost.tsx b/src/components/InjectedComponents/DecryptedPost/DecryptedPost.tsx index df99bd222cf6..d5fb282b7297 100644 --- a/src/components/InjectedComponents/DecryptedPost/DecryptedPost.tsx +++ b/src/components/InjectedComponents/DecryptedPost/DecryptedPost.tsx @@ -16,6 +16,7 @@ import { DecryptPostFailedProps, DecryptPostFailed } from './DecryptPostFailed' import { DecryptedPostDebug } from './DecryptedPostDebug' import { usePostInfoDetails } from '../../DataSource/usePostInfo' import { asyncIteratorWithResult } from '../../../utils/type-transform/asyncIteratorHelpers' +import { hmr } from '../../../utils/hmr-react' export interface DecryptPostProps { onDecrypted: (post: TypedMessage, raw: string) => void @@ -31,7 +32,7 @@ export interface DecryptPostProps { failedComponent?: React.ComponentType failedComponentProps?: Partial } -export function DecryptPost(props: DecryptPostProps) { +export const DecryptPost = hmr(function DecryptPost(props: DecryptPostProps) { const { whoAmI, encryptedText, profiles, alreadySelectedPreviously, onDecrypted } = props const postBy = usePostInfoDetails('postBy') const Success = props.successComponent || DecryptPostSuccess @@ -133,4 +134,4 @@ export function DecryptPost(props: DecryptPostProps) { ) } -} +}, import.meta) diff --git a/src/extension/options-page/DeveloperComponents/DecryptPost.tsx b/src/extension/options-page/DeveloperComponents/DecryptPost.tsx index 8bed865dde62..9e2a1e534e48 100644 --- a/src/extension/options-page/DeveloperComponents/DecryptPost.tsx +++ b/src/extension/options-page/DeveloperComponents/DecryptPost.tsx @@ -44,7 +44,7 @@ export function DecryptPostDeveloperMode() { {}} + onDecrypted={() => {}} profiles={[]} whoAmI={whoAmIIdentifier} /> diff --git a/src/extension/options-page/index.tsx b/src/extension/options-page/index.tsx index 2c725d2ac09d..0a34ad9d1347 100644 --- a/src/extension/options-page/index.tsx +++ b/src/extension/options-page/index.tsx @@ -137,7 +137,7 @@ function DashboardUI() { <> {xsMatched ? null : drawer} - {webpackEnv.perferResponsiveTarget === 'xs' ? ( + {UseMediaQueryDefaultMatches ? ( ) : null} @@ -149,11 +149,7 @@ function DashboardUI() { diff --git a/src/utils/hmr-client.ts b/src/utils/hmr-client.ts new file mode 100644 index 000000000000..daf918dcae02 --- /dev/null +++ b/src/utils/hmr-client.ts @@ -0,0 +1,24 @@ +import { Emitter } from '@servie/events' +import { sideEffect } from './side-effects' +sideEffect.then(() => { + if (process.env.NODE_ENV === 'production') return undefined + const ws = new WebSocket('ws://localhost:7687') + console.log('HMR client started') + ws.addEventListener('message', async (e) => { + const url = browser.runtime.getURL(e.data) + console.log(e.data, 'updated') + try { + const newModule = await import(url + `?now=${Date.now()}`) + event.emit(url, newModule) + } catch (e) { + console.warn(e.data, 'update failed!', e) + } + }) + return ws +}) +const event = new Emitter() +export function registerHMR(meta: ImportMeta, onUpdate: () => void) { + const normalizedURL = meta.url.split('?')[0] + event.on(normalizedURL, onUpdate) + return () => event.off(normalizedURL, onUpdate) +} diff --git a/src/utils/hmr-react.tsx b/src/utils/hmr-react.tsx new file mode 100644 index 000000000000..196e6f716753 --- /dev/null +++ b/src/utils/hmr-react.tsx @@ -0,0 +1,35 @@ +import React, { useEffect, useRef, useState } from 'react' +import { registerHMR } from './hmr-client' +import { useUpdate } from 'react-use' +const symb = Symbol.for('HMR') +// Future work: React refresh https://github.com/facebook/react/issues/16604#issuecomment-528663101 +export function hmr(component: T, meta: ImportMeta, key = component.name): typeof component { + if (process.env.NODE_ENV === 'production') return component + let Component = component + const WrappedElement = React.forwardRef((props, ref: any) => { + const C = useRef(Component) + const refresh = useUpdate() + useEffect(() => { + return registerHMR(meta, async () => { + const newModule = await import(meta.url + '?now' + Date.now()) + if (!newModule[key]) + return console.warn( + 'HMR: please ensure the export function name is', + key, + 'or you can provide the third function to specify one.', + ) + Component = newModule[key][symb] + C.current = Component + refresh() + }) + }) + return + }) + // @ts-ignore + WrappedElement.displayName = (Component.displayName || Component.name) + ' (HMR)' + // @ts-ignore + WrappedElement.defaultProps = Component.defaultProps + // @ts-ignore + WrappedElement[symb] = component + return WrappedElement as any +} diff --git a/tsconfig.json b/tsconfig.json index 06f910859f1a..4f979ed5332a 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,4 +1,5 @@ { + "exclude": ["node_modules/**/*"], "compilerOptions": { // entry "rootDirs": ["./src/"], diff --git a/yarn.lock b/yarn.lock index 365415c82e25..4649c42b1f85 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2943,6 +2943,21 @@ dependencies: "@types/node" "*" +"@types/gulp-changed@^0.0.33": + version "0.0.33" + resolved "https://registry.yarnpkg.com/@types/gulp-changed/-/gulp-changed-0.0.33.tgz#ded31a346321fe30258e6d7e6ad71842732ca92f" + integrity sha512-HgX/ywK6WVi7ho7y210I4tEmzC0hLor1F/S4FFXRA4eaFodp1XPMNb1EpgXHO7ySr4ZGY8I1KRRqtu/A2fNhSQ== + dependencies: + "@types/node" "*" + "@types/vinyl" "*" + +"@types/gulp-rename@^0.0.33": + version "0.0.33" + resolved "https://registry.yarnpkg.com/@types/gulp-rename/-/gulp-rename-0.0.33.tgz#38d146e97786569f74f5391a1b1f9b5198674b6c" + integrity sha512-FIZQvbZJj6V1gHPTzO+g/BCWpDur7fJrroae4gwV3LaoHBQ+MrR9sB+2HssK8fHv4WdY6hVNxkcft9bYatuPIA== + dependencies: + "@types/node" "*" + "@types/gulp-zip@^4.0.1": version "4.0.1" resolved "https://registry.yarnpkg.com/@types/gulp-zip/-/gulp-zip-4.0.1.tgz#96cd0b994219f9ae3bbbec7ec3baa043fba9d9ef" @@ -3282,6 +3297,14 @@ dependencies: "@types/node" "*" +"@types/rimraf@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/rimraf/-/rimraf-3.0.0.tgz#b9d03f090ece263671898d57bb7bb007023ac19f" + integrity sha512-7WhJ0MdpFgYQPXlF4Dx+DhgvlPCfz/x5mHaeDQAKhcenvQP1KCpLQ18JklAqeGMYSAT2PxLpzd0g2/HE7fj7hQ== + dependencies: + "@types/glob" "*" + "@types/node" "*" + "@types/source-list-map@*": version "0.1.2" resolved "https://registry.yarnpkg.com/@types/source-list-map/-/source-list-map-0.1.2.tgz#0078836063ffaf17412349bba364087e0ac02ec9" @@ -3402,6 +3425,13 @@ "@types/webpack-sources" "*" source-map "^0.6.0" +"@types/ws@^7.2.6": + version "7.2.6" + resolved "https://registry.yarnpkg.com/@types/ws/-/ws-7.2.6.tgz#516cbfb818310f87b43940460e065eb912a4178d" + integrity sha512-Q07IrQUSNpr+cXU4E4LtkSIBPie5GLZyyMC1QtQYRLWz701+XcoVygGUZgvLqElq1nU4ICldMYPnexlBsg3dqQ== + dependencies: + "@types/node" "*" + "@types/yargs-parser@*": version "13.1.0" resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-13.1.0.tgz#c563aa192f39350a1d18da36c5a8da382bbd8228" @@ -9893,6 +9923,17 @@ gud@^1.0.0: resolved "https://registry.yarnpkg.com/gud/-/gud-1.0.0.tgz#a489581b17e6a70beca9abe3ae57de7a499852c0" integrity sha512-zGEOVKFM5sVPPrYs7J5/hYEw2Pof8KCyOwyhG8sAF26mCAeUFAcYPu1mwB7hhpIP29zOIBaDqwuHdLp0jvZXjw== +gulp-changed@^4.0.2: + version "4.0.2" + resolved "https://registry.yarnpkg.com/gulp-changed/-/gulp-changed-4.0.2.tgz#387c6b05a3d18519281516ebf8f49f2d5d56efd3" + integrity sha512-rAvQt+ByaqrMuJLwucvxC+MC02Vh8ksiJ16hoQlk4xnmlHiLJMque2aXXQMmyocQac3RIjNRcyr7iG1TNH15GA== + dependencies: + make-dir "^3.0.0" + plugin-error "^1.0.1" + replace-ext "^1.0.0" + through2 "^3.0.1" + touch "^3.1.0" + gulp-cli@^2.2.0: version "2.2.0" resolved "https://registry.yarnpkg.com/gulp-cli/-/gulp-cli-2.2.0.tgz#5533126eeb7fe415a7e3e84a297d334d5cf70ebc" @@ -13718,6 +13759,13 @@ nopt@^4.0.1: abbrev "1" osenv "^0.1.4" +nopt@~1.0.10: + version "1.0.10" + resolved "https://registry.yarnpkg.com/nopt/-/nopt-1.0.10.tgz#6ddd21bd2a31417b92727dd585f8a6f37608ebee" + integrity sha1-bd0hvSoxQXuScn3Vhfim83YI6+4= + dependencies: + abbrev "1" + normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -18440,6 +18488,13 @@ tosource@1.0.0: resolved "https://registry.yarnpkg.com/tosource/-/tosource-1.0.0.tgz#42d88dd116618bcf00d6106dd5446f3427902ff1" integrity sha1-QtiN0RZhi88A1hBt1URvNCeQL/E= +touch@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/touch/-/touch-3.1.0.tgz#fe365f5f75ec9ed4e56825e0bb76d24ab74af83b" + integrity sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA== + dependencies: + nopt "~1.0.10" + tough-cookie@^2.3.3, tough-cookie@^2.3.4, tough-cookie@^2.5.0, tough-cookie@~2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" @@ -20300,6 +20355,11 @@ ws@^7, ws@^7.2.1, ws@^7.2.3: resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.0.tgz#4b2f7f219b3d3737bc1a2fbf145d825b94d38ffd" integrity sha512-iFtXzngZVXPGgpTlP1rBqsUK82p9tKqsWRPg5L56egiljujJT3vGAYnHANvFxBieXrTFavhzhxW52jnaWV+w2w== +ws@^7.3.1: + version "7.3.1" + resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8" + integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA== + xdg-basedir@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/xdg-basedir/-/xdg-basedir-3.0.0.tgz#496b2cc109eca8dbacfe2dc72b603c17c5870ad4"