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.

{ routesPaths = [routes.routesPath]; } - // add vite plugin for redirect page component + function getImportDeclarations() { + return api.getValue('importDeclarations'); + } if (vite) { - modifyUserConfig('vite.plugins', [vitePluginPageRedirect(rootDir, routesPaths)], { deepmerge: true }); + modifyUserConfig( + 'vite.plugins', + [vitePluginPageRedirect(rootDir, routesPaths), vitePluginImportRedirect(getImportDeclarations)], + { 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..6f8dfe6a0 --- /dev/null +++ b/packages/plugin-store/src/vitePluginImportRedirect.ts @@ -0,0 +1,96 @@ +import { Plugin } from 'vite'; +import MagicString from 'magic-string'; +import { init, parse } from 'es-module-lexer'; + +/** + * Redirect API import source from 'ice' to real path in store file + */ +function vitePluginImportRedirect(getImportDeclarations): Plugin { + let needSourcemap = false; + const importDeclarations = getImportDeclarations(); + + return { + enforce: 'post', // after transformed ts file to avoid ts syntax error + name: 'vite-plugin-store-import-redirect', + configResolved(resolvedConfig) { + needSourcemap = !!resolvedConfig.build.sourcemap; + }, + 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); + + for (let index = 0; index < imports.length; index++) { + const importSpecifier = imports[index]; + 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); + /** + * need to match 3 cases: + * 1. import { createStore } from 'ice'; + * 2. import { createStore, request } from 'ice'; + * 3. import { + * createStore, + * request, + * } from 'ice'; + */ + 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'] } + */ + 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 { + // 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(), + }; + } + return null; + } + }; +} + +export default vitePluginImportRedirect;