From 857778e01a4da048f54b37225bfc6ffe5c5cd1a9 Mon Sep 17 00:00:00 2001 From: luhc228 Date: Wed, 10 Nov 2021 16:37:26 +0800 Subject: [PATCH 1/8] fix: store error in vite HMR --- packages/icejs/package.json | 2 +- packages/plugin-store/CHANGELOG.md | 4 +++ packages/plugin-store/package.json | 9 ++--- packages/plugin-store/src/index.ts | 7 +++- .../src/vitePluginImportRedirect.ts | 33 +++++++++++++++++++ 5 files changed, 49 insertions(+), 6 deletions(-) create mode 100644 packages/plugin-store/src/vitePluginImportRedirect.ts diff --git a/packages/icejs/package.json b/packages/icejs/package.json index 23b63a42f..a725a5942 100644 --- a/packages/icejs/package.json +++ b/packages/icejs/package.json @@ -33,7 +33,7 @@ "build-plugin-ice-request": "2.0.0", "build-plugin-ice-router": "2.0.1", "build-plugin-ice-ssr": "3.0.1", - "build-plugin-ice-store": "2.0.3", + "build-plugin-ice-store": "2.0.4", "build-plugin-react-app": "2.0.3", "build-plugin-pwa": "1.0.0", "chalk": "^4.1.0", diff --git a/packages/plugin-store/CHANGELOG.md b/packages/plugin-store/CHANGELOG.md index 6f46260dc..82137b8c1 100644 --- a/packages/plugin-store/CHANGELOG.md +++ b/packages/plugin-store/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 2.0.4 + +- [fix] store error in vite HMR + ## 2.0.3 - [fix] nested routes not render in vite mode diff --git a/packages/plugin-store/package.json b/packages/plugin-store/package.json index 45167b32d..1553f2059 100644 --- a/packages/plugin-store/package.json +++ b/packages/plugin-store/package.json @@ -1,7 +1,7 @@ { "name": "build-plugin-ice-store", - "version": "2.0.3", - "description": "builtin `icestore` in icejs", + "version": "2.0.4", + "description": "builtin `@ice/store` in icejs", "author": "ice-admin@alibaba-inc.com", "homepage": "https://github.com/alibaba/ice#readme", "license": "MIT", @@ -31,9 +31,10 @@ "fs-extra": "^8.1.0", "fs-readdir-recursive": "^1.1.0", "globby": "^11.0.1", - "loader-utils": "^2.0.0" + "loader-utils": "^2.0.0", + "magic-string": "^0.25.7" }, "devDependencies": { "vite": "^2.4.3" } -} \ No newline at end of file +} diff --git a/packages/plugin-store/src/index.ts b/packages/plugin-store/src/index.ts index e3c371615..6da04b1e3 100644 --- a/packages/plugin-store/src/index.ts +++ b/packages/plugin-store/src/index.ts @@ -5,6 +5,7 @@ import checkStoreExists from './utils/checkStoreExists'; import { getAppStorePath } from './utils/getPath'; import { getRouteFileType } from './utils/getFileType'; import vitePluginPageRedirect from './vitePluginPageRedirect'; +import vitePluginImportRedirect from './vitePluginImportRedirect'; const { name: pluginName } = require('../package.json'); @@ -81,7 +82,11 @@ export default async (api: any) => { // add vite plugin for redirect page component if (vite) { - modifyUserConfig('vite.plugins', [vitePluginPageRedirect(rootDir, routesPaths)], { deepmerge: true }); + modifyUserConfig( + 'vite.plugins', + [vitePluginPageRedirect(rootDir, routesPaths), vitePluginImportRedirect()], + { deepmerge: true } + ); } if (swc) { diff --git a/packages/plugin-store/src/vitePluginImportRedirect.ts b/packages/plugin-store/src/vitePluginImportRedirect.ts new file mode 100644 index 000000000..7a79c3884 --- /dev/null +++ b/packages/plugin-store/src/vitePluginImportRedirect.ts @@ -0,0 +1,33 @@ +import { Plugin } from 'vite'; +import MagicString from 'magic-string'; + +function vitePluginImportRedirect(): Plugin { + let needSourcemap = false; + + return { + enforce: 'pre', + name: 'vite-plugin-store-import-redirect', + configResolved(resolvedConfig) { + needSourcemap = !!resolvedConfig.build.sourcemap; + }, + transform(code, id) { + const appStoreRegExp = /src\/store.(?:j|t)s$/; + const pageStoreRegExp = /src\/pages\/(?:\w+)\/store.(?:j|t)s$/; + if (appStoreRegExp.test(id) || pageStoreRegExp.test(id)) { + const s = new MagicString(code); + const matchedResult = code.match(/(createStore\s*,?)(?:.*)} from (?:"|')ice(?:'|")/); + if (matchedResult) { + s.overwrite(matchedResult.index, matchedResult.index + matchedResult[1].length, ''); + s.prepend('import { createStore } from "@ice/store";\n'); + } + return { + map: needSourcemap ? s.generateMap({ hires: true }) : null, + code: s.toString(), + }; + } + return null; + } + }; +} + +export default vitePluginImportRedirect; From 50948d0c9a9b3c62b2c90e68ed4db9e2e25afc6e Mon Sep 17 00:00:00 2001 From: luhc228 Date: Wed, 10 Nov 2021 16:43:26 +0800 Subject: [PATCH 2/8] fix: regexp --- examples/basic-vite/src/pages/Home/index.tsx | 2 +- packages/plugin-store/src/vitePluginImportRedirect.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/basic-vite/src/pages/Home/index.tsx b/examples/basic-vite/src/pages/Home/index.tsx index efec10e8b..b9f28af65 100644 --- a/examples/basic-vite/src/pages/Home/index.tsx +++ b/examples/basic-vite/src/pages/Home/index.tsx @@ -16,7 +16,7 @@ function App() { 🪂 Click me : {count} -

Don't forgot to install AppWorks in Your Vscode.

+

Don't forget to install AppWorks in Your Vscode.

Date: Wed, 10 Nov 2021 16:51:45 +0800 Subject: [PATCH 3/8] chore: add annotation --- packages/plugin-store/src/vitePluginImportRedirect.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/packages/plugin-store/src/vitePluginImportRedirect.ts b/packages/plugin-store/src/vitePluginImportRedirect.ts index 2b09548ff..ad6f1218f 100644 --- a/packages/plugin-store/src/vitePluginImportRedirect.ts +++ b/packages/plugin-store/src/vitePluginImportRedirect.ts @@ -1,6 +1,9 @@ import { Plugin } from 'vite'; import MagicString from 'magic-string'; +/** + * Redirect createStore API import source from 'ice' to '@ice/store'; + */ function vitePluginImportRedirect(): Plugin { let needSourcemap = false; @@ -17,6 +20,13 @@ function vitePluginImportRedirect(): Plugin { const s = new MagicString(code); const matchedResult = code.match(/(createStore\s*,?).*} from ["']ice['"]/); if (matchedResult) { + /** + * before: import { createStore, Plugin } from 'ice'; + * + * after: + * import { Plugin } from 'ice'; + * import { createStore } from '@ice/store'; + */ s.overwrite(matchedResult.index, matchedResult.index + matchedResult[1].length, ''); s.prepend('import { createStore } from "@ice/store";\n'); } From 5a6f9a1e8dfa8869bbc54c8f5aa3aff6c34bad7c Mon Sep 17 00:00:00 2001 From: luhc228 Date: Wed, 10 Nov 2021 17:02:13 +0800 Subject: [PATCH 4/8] fix: comment --- packages/plugin-store/src/vitePluginImportRedirect.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/plugin-store/src/vitePluginImportRedirect.ts b/packages/plugin-store/src/vitePluginImportRedirect.ts index ad6f1218f..669c83281 100644 --- a/packages/plugin-store/src/vitePluginImportRedirect.ts +++ b/packages/plugin-store/src/vitePluginImportRedirect.ts @@ -18,7 +18,7 @@ function vitePluginImportRedirect(): Plugin { const pageStoreRegExp = /src\/pages\/\w+\/store.[jt]s$/; if (appStoreRegExp.test(id) || pageStoreRegExp.test(id)) { const s = new MagicString(code); - const matchedResult = code.match(/(createStore\s*,?).*} from ["']ice['"]/); + const matchedResult = code.match(/(createStore\s*,?).*}\s+from\s+["']ice['"]/); if (matchedResult) { /** * before: import { createStore, Plugin } from 'ice'; From 0e2fb6d76f5cdc8487992e91de2b39c7dfe9b1ba Mon Sep 17 00:00:00 2001 From: luhc228 Date: Wed, 10 Nov 2021 20:15:39 +0800 Subject: [PATCH 5/8] feat: support redirect other API in store --- packages/plugin-store/package.json | 1 + packages/plugin-store/src/index.ts | 6 +- .../src/vitePluginImportRedirect.ts | 69 +++++++++++++++---- 3 files changed, 62 insertions(+), 14 deletions(-) diff --git a/packages/plugin-store/package.json b/packages/plugin-store/package.json index 1553f2059..382313647 100644 --- a/packages/plugin-store/package.json +++ b/packages/plugin-store/package.json @@ -28,6 +28,7 @@ "@ice/store": "^2.0.0-3", "chalk": "^4.1.0", "enhanced-resolve": "^4.3.0", + "es-module-lexer": "^0.9.3", "fs-extra": "^8.1.0", "fs-readdir-recursive": "^1.1.0", "globby": "^11.0.1", diff --git a/packages/plugin-store/src/index.ts b/packages/plugin-store/src/index.ts index 6da04b1e3..896b91ea2 100644 --- a/packages/plugin-store/src/index.ts +++ b/packages/plugin-store/src/index.ts @@ -80,11 +80,13 @@ export default async (api: any) => { routesPaths = [routes.routesPath]; } - // add vite plugin for redirect page component + function getImportDeclarations() { + return api.getValue('importDeclarations'); + } if (vite) { modifyUserConfig( 'vite.plugins', - [vitePluginPageRedirect(rootDir, routesPaths), vitePluginImportRedirect()], + [vitePluginPageRedirect(rootDir, routesPaths), vitePluginImportRedirect(getImportDeclarations)], { deepmerge: true } ); } diff --git a/packages/plugin-store/src/vitePluginImportRedirect.ts b/packages/plugin-store/src/vitePluginImportRedirect.ts index 669c83281..ee1284f55 100644 --- a/packages/plugin-store/src/vitePluginImportRedirect.ts +++ b/packages/plugin-store/src/vitePluginImportRedirect.ts @@ -1,11 +1,13 @@ import { Plugin } from 'vite'; import MagicString from 'magic-string'; +import { init, parse } from 'es-module-lexer'; /** - * Redirect createStore API import source from 'ice' to '@ice/store'; + * Redirect API import source from 'ice' to real path in store file */ -function vitePluginImportRedirect(): Plugin { +function vitePluginImportRedirect(getImportDeclarations): Plugin { let needSourcemap = false; + const importDeclarations = getImportDeclarations(); return { enforce: 'pre', @@ -13,23 +15,66 @@ function vitePluginImportRedirect(): Plugin { configResolved(resolvedConfig) { needSourcemap = !!resolvedConfig.build.sourcemap; }, - transform(code, id) { + async transform(code, id) { const appStoreRegExp = /src\/store.[jt]s$/; const pageStoreRegExp = /src\/pages\/\w+\/store.[jt]s$/; if (appStoreRegExp.test(id) || pageStoreRegExp.test(id)) { + await init; + const [imports] = parse(code); const s = new MagicString(code); - const matchedResult = code.match(/(createStore\s*,?).*}\s+from\s+["']ice['"]/); - if (matchedResult) { + for (let index = 0; index < imports.length; index++) { + const importSpecifier = imports[0]; + const importSource = code.substring(importSpecifier.s, importSpecifier.e); + if (importSource !== 'ice') { + // eslint-disable-next-line no-continue + continue; + } + const importStr = code.substring(importSpecifier.ss, importSpecifier.se); /** - * before: import { createStore, Plugin } from 'ice'; - * - * after: - * import { Plugin } from 'ice'; - * import { createStore } from '@ice/store'; + * need to match 3 cases: + * 1. import { createStore } from 'ice'; + * 2. import { createStore, request } from 'ice'; + * 3. import { + * createStore, + * request, + * } from 'ice'; */ - s.overwrite(matchedResult.index, matchedResult.index + matchedResult[1].length, ''); - s.prepend('import { createStore } from "@ice/store";\n'); + const matchedResult = importStr.match(/{([\s\S]*)}\s+from\s+["']ice['"]/); + if (matchedResult) { + const [, importIdentifiersStr] = matchedResult; + const replaceSpaceImportIdentifiersStr = importIdentifiersStr.replace(/\s+/g, ''); + const importIdentifiersArray = replaceSpaceImportIdentifiersStr.split(',').filter(item => item); + + let newImportStr = ''; + /** + * e.g.: importDeclarationSources = { '@ice/store': ['createStore', 'IStore'] } + */ + const normalImportSources: { [key: string]: string[] } = {}; + + importIdentifiersArray.forEach((importIdentifier: string) => { + const { value, type } = importDeclarations[importIdentifier]; + if (type === 'default') { + newImportStr += `import ${importIdentifier} from '${value}';\n`; + } else { + // handle normal import + // eslint-disable-next-line no-lonely-if + if (normalImportSources[value]) { + normalImportSources[value].push(importIdentifier); + } else { + normalImportSources[value] = [importIdentifier]; + } + } + }); + // generate normal import strings + Object.keys(normalImportSources).forEach(sourceKey => { + const importIdentifiers = normalImportSources[sourceKey]; + newImportStr += `import { ${importIdentifiers.join(', ')} } from '${sourceKey}';\n`; + }); + // overwrite `import { xxx } from 'ice';` statement + s.overwrite(importSpecifier.ss, importSpecifier.se, newImportStr); + } } + return { map: needSourcemap ? s.generateMap({ hires: true }) : null, code: s.toString(), From 517ef86ab15f06678a84e4ed097346be666a2c42 Mon Sep 17 00:00:00 2001 From: luhc228 Date: Wed, 10 Nov 2021 22:17:21 +0800 Subject: [PATCH 6/8] fix: enforce value, import declaration undefined --- .../src/vitePluginImportRedirect.ts | 22 +++++++++++++------ 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/packages/plugin-store/src/vitePluginImportRedirect.ts b/packages/plugin-store/src/vitePluginImportRedirect.ts index ee1284f55..6f8dfe6a0 100644 --- a/packages/plugin-store/src/vitePluginImportRedirect.ts +++ b/packages/plugin-store/src/vitePluginImportRedirect.ts @@ -10,7 +10,7 @@ function vitePluginImportRedirect(getImportDeclarations): Plugin { const importDeclarations = getImportDeclarations(); return { - enforce: 'pre', + enforce: 'post', // after transformed ts file to avoid ts syntax error name: 'vite-plugin-store-import-redirect', configResolved(resolvedConfig) { needSourcemap = !!resolvedConfig.build.sourcemap; @@ -22,8 +22,9 @@ function vitePluginImportRedirect(getImportDeclarations): Plugin { await init; const [imports] = parse(code); const s = new MagicString(code); + for (let index = 0; index < imports.length; index++) { - const importSpecifier = imports[0]; + const importSpecifier = imports[index]; const importSource = code.substring(importSpecifier.s, importSpecifier.e); if (importSource !== 'ice') { // eslint-disable-next-line no-continue @@ -49,10 +50,17 @@ function vitePluginImportRedirect(getImportDeclarations): Plugin { /** * e.g.: importDeclarationSources = { '@ice/store': ['createStore', 'IStore'] } */ - const normalImportSources: { [key: string]: string[] } = {}; - - importIdentifiersArray.forEach((importIdentifier: string) => { - const { value, type } = importDeclarations[importIdentifier]; + let normalImportSources: { [key: string]: string[] } = {}; + + for (let idx = 0; idx < importIdentifiersArray.length; idx++) { + const importIdentifier = importIdentifiersArray[idx]; + const importDeclaration = importDeclarations[importIdentifier]; + if (!importDeclaration) { + console.log(`[vite-plugin-store-import-redirect]: Don't recognize the importIdentifier '${importIdentifier}'. Stop transforming import declaration.`); + normalImportSources = {}; // set to `{}` for not to generate normal import strings + break; + } + const { value, type } = importDeclaration; if (type === 'default') { newImportStr += `import ${importIdentifier} from '${value}';\n`; } else { @@ -64,7 +72,7 @@ function vitePluginImportRedirect(getImportDeclarations): Plugin { normalImportSources[value] = [importIdentifier]; } } - }); + } // generate normal import strings Object.keys(normalImportSources).forEach(sourceKey => { const importIdentifiers = normalImportSources[sourceKey]; From 9ad0e18480936872cedb10b5937f91ccc53b527e Mon Sep 17 00:00:00 2001 From: luhc228 Date: Fri, 12 Nov 2021 11:37:55 +0800 Subject: [PATCH 7/8] chore: update icejs version --- packages/icejs/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/icejs/package.json b/packages/icejs/package.json index a725a5942..435ef5858 100644 --- a/packages/icejs/package.json +++ b/packages/icejs/package.json @@ -1,6 +1,6 @@ { "name": "ice.js", - "version": "2.1.2", + "version": "2.1.3", "description": "command line interface and builtin plugin for icejs", "author": "ice-admin@alibaba-inc.com", "homepage": "", @@ -33,7 +33,7 @@ "build-plugin-ice-request": "2.0.0", "build-plugin-ice-router": "2.0.1", "build-plugin-ice-ssr": "3.0.1", - "build-plugin-ice-store": "2.0.4", + "build-plugin-ice-store": "2.0.4-beta.0", "build-plugin-react-app": "2.0.3", "build-plugin-pwa": "1.0.0", "chalk": "^4.1.0", From fe112f671f9acfeee7dc382229719f942b15621d Mon Sep 17 00:00:00 2001 From: luhc228 Date: Fri, 12 Nov 2021 11:44:55 +0800 Subject: [PATCH 8/8] chore: remove beta version --- packages/icejs/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/icejs/package.json b/packages/icejs/package.json index 435ef5858..8a32dfe0e 100644 --- a/packages/icejs/package.json +++ b/packages/icejs/package.json @@ -33,7 +33,7 @@ "build-plugin-ice-request": "2.0.0", "build-plugin-ice-router": "2.0.1", "build-plugin-ice-ssr": "3.0.1", - "build-plugin-ice-store": "2.0.4-beta.0", + "build-plugin-ice-store": "2.0.4", "build-plugin-react-app": "2.0.3", "build-plugin-pwa": "1.0.0", "chalk": "^4.1.0",