mirror of https://github.com/alibaba/ice.git
				
				
				
			Refactor: use swc plugin to remove code (#6144)
* refactor: use swc plugin to remove code * chore: update version
This commit is contained in:
		
							parent
							
								
									ce94e05489
								
							
						
					
					
						commit
						5dd3c86ed7
					
				|  | @ -0,0 +1,6 @@ | |||
| --- | ||||
| '@ice/webpack-config': patch | ||||
| '@ice/app': patch | ||||
| --- | ||||
| 
 | ||||
| refactor: use swc plugin for remove code | ||||
|  | @ -0,0 +1,5 @@ | |||
| --- | ||||
| '@ice/bundles': patch | ||||
| --- | ||||
| 
 | ||||
| fix: update version of @ice/swc-plugin-keep-export(0.1.4-2) | ||||
|  | @ -17,7 +17,7 @@ | |||
|   "dependencies": { | ||||
|     "@swc/core": "1.3.19", | ||||
|     "@ice/swc-plugin-remove-export": "0.1.2", | ||||
|     "@ice/swc-plugin-keep-export": "0.1.4", | ||||
|     "@ice/swc-plugin-keep-export": "0.1.4-2", | ||||
|     "@ice/swc-plugin-node-transform": "0.1.0-5", | ||||
|     "ansi-html-community": "^0.0.8", | ||||
|     "html-entities": "^2.3.2", | ||||
|  |  | |||
|  | @ -36,10 +36,6 @@ | |||
|   "bugs": "https://github.com/alibaba/ice/issues", | ||||
|   "homepage": "https://v3.ice.work", | ||||
|   "dependencies": { | ||||
|     "@babel/generator": "7.18.10", | ||||
|     "@babel/parser": "7.18.10", | ||||
|     "@babel/traverse": "7.18.10", | ||||
|     "@babel/types": "7.18.10", | ||||
|     "@ice/bundles": "0.1.8", | ||||
|     "@ice/route-manifest": "1.1.1", | ||||
|     "@ice/runtime": "^1.1.5", | ||||
|  | @ -56,7 +52,6 @@ | |||
|     "dotenv": "^16.0.0", | ||||
|     "dotenv-expand": "^8.0.3", | ||||
|     "ejs": "^3.1.6", | ||||
|     "estree-walker": "^3.0.2", | ||||
|     "fast-glob": "^3.2.11", | ||||
|     "find-up": "^5.0.0", | ||||
|     "fs-extra": "^10.0.0", | ||||
|  |  | |||
|  | @ -1,55 +0,0 @@ | |||
| import * as fs from 'fs'; | ||||
| import type { Plugin } from 'esbuild'; | ||||
| import { parse, type ParserOptions } from '@babel/parser'; | ||||
| import babelTraverse from '@babel/traverse'; | ||||
| import babelGenerate from '@babel/generator'; | ||||
| import removeTopLevelCode from '../utils/babelPluginRemoveCode.js'; | ||||
| import formatPath from '../utils/formatPath.js'; | ||||
| import { logger } from '../utils/logger.js'; | ||||
| 
 | ||||
| // @ts-ignore @babel/traverse is not a valid export in esm
 | ||||
| const traverse = babelTraverse.default || babelTraverse; | ||||
| // @ts-ignore @babel/generate is not a valid export in esm
 | ||||
| const generate = babelGenerate.default || babelGenerate; | ||||
| 
 | ||||
| const removeCodePlugin = (keepExports: string[], transformInclude: (id: string) => boolean): Plugin => { | ||||
|   const parserOptions: ParserOptions = { | ||||
|     sourceType: 'module', | ||||
|     plugins: [ | ||||
|       'jsx', | ||||
|       'importMeta', | ||||
|       'topLevelAwait', | ||||
|       'classProperties', | ||||
|       'classPrivateMethods', | ||||
|     ], | ||||
|   }; | ||||
|   return { | ||||
|     name: 'esbuild-remove-top-level-code', | ||||
|     setup(build) { | ||||
|       build.onLoad({ filter: /\.(js|jsx|ts|tsx)$/ }, async ({ path: id }) => { | ||||
|         if (!transformInclude(formatPath(id))) { | ||||
|           return; | ||||
|         } | ||||
|         const source = await fs.promises.readFile(id, 'utf-8'); | ||||
|         let isTS = false; | ||||
|         if (id.match(/\.(ts|tsx)$/)) { | ||||
|           isTS = true; | ||||
|           parserOptions.plugins.push('typescript', 'decorators-legacy'); | ||||
|         } | ||||
|         try { | ||||
|           const ast = parse(source, parserOptions); | ||||
|           traverse(ast, removeTopLevelCode(keepExports)); | ||||
|           const contents = generate(ast).code; | ||||
|           return { | ||||
|             contents, | ||||
|             loader: isTS ? 'tsx' : 'jsx', | ||||
|           }; | ||||
|         } catch (error) { | ||||
|           logger.debug('Remove top level code error.', `\nFile id: ${id}`, `\n${error.stack}`); | ||||
|         } | ||||
|       }); | ||||
|     }, | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| export default removeCodePlugin; | ||||
|  | @ -1,7 +1,6 @@ | |||
| import * as path from 'path'; | ||||
| import fs from 'fs-extra'; | ||||
| import type { ServerCompiler } from '../types/plugin.js'; | ||||
| import removeTopLevelCode from '../esbuild/removeTopLevelCode.js'; | ||||
| import { getCache, setCache } from '../utils/persistentCache.js'; | ||||
| import { getFileHash } from '../utils/hash.js'; | ||||
| import dynamicImport from '../utils/dynamicImport.js'; | ||||
|  | @ -15,7 +14,7 @@ type GetOutfile = (entry: string, exportNames: string[]) => string; | |||
| interface CompileConfig { | ||||
|   entry: string; | ||||
|   rootDir: string; | ||||
|   transformInclude: (id: string) => boolean; | ||||
|   transformInclude?: (id: string) => boolean; | ||||
|   needRecompile?: (entry: string, options: string[]) => Promise<boolean | string>; | ||||
|   getOutfile?: GetOutfile; | ||||
| } | ||||
|  | @ -48,13 +47,19 @@ class Config { | |||
|         format: 'esm', | ||||
|         outfile, | ||||
|         plugins: [ | ||||
|           removeTopLevelCode(keepExports, transformInclude), | ||||
|           // External node builtin modules, such as `fs`, it will be imported by weex document.
 | ||||
|           externalBuiltinPlugin(), | ||||
|         ], | ||||
|         ].filter(Boolean), | ||||
|         sourcemap: false, | ||||
|         logLevel: 'silent', // The main server compiler process will log it.
 | ||||
|       }, {}); | ||||
|       }, { | ||||
|         swc: { | ||||
|           keepExports: { | ||||
|             value: keepExports, | ||||
|             include: transformInclude, | ||||
|           }, | ||||
|         }, | ||||
|       }); | ||||
|       if (!error) { | ||||
|         this.status = 'RESOLVED'; | ||||
|         return outfile; | ||||
|  | @ -197,8 +202,6 @@ export const getRouteExportConfig = (rootDir: string) => { | |||
|     entry: routeConfigFile, | ||||
|     rootDir, | ||||
|     getOutfile: getRouteConfigOutfile, | ||||
|     // Only remove top level code for route component file.
 | ||||
|     transformInclude: (id) => id.includes('src/pages'), | ||||
|     needRecompile: async (entry) => { | ||||
|       let cached = false; | ||||
|       try { | ||||
|  | @ -218,8 +221,6 @@ export const getRouteExportConfig = (rootDir: string) => { | |||
|     entry: loadersConfigFile, | ||||
|     rootDir, | ||||
|     getOutfile: getdataLoadersConfigOutfile, | ||||
|     // Only remove top level code for route component file.
 | ||||
|     transformInclude: (id) => id.includes('src/pages'), | ||||
|     needRecompile: async (entry) => { | ||||
|       let cached = false; | ||||
|       const cachedKey = `loader_config_file_${process.env.__ICE_VERSION__}`; | ||||
|  |  | |||
|  | @ -1,128 +0,0 @@ | |||
| import type { NodePath } from '@babel/traverse'; | ||||
| import * as t from '@babel/types'; | ||||
| 
 | ||||
| const removeUnreferencedCode = (nodePath: NodePath<t.Program>) => { | ||||
|   let hasRemoved = false; | ||||
| 
 | ||||
|   // Update bindings removed in enter hooks.
 | ||||
|   nodePath.scope.crawl(); | ||||
|   for (const [, binding] of Object.entries(nodePath.scope.bindings)) { | ||||
|     if (!binding.referenced && binding.path.node) { | ||||
|       const nodeType = binding.path.node.type; | ||||
|       if (['VariableDeclarator', 'ImportSpecifier', 'FunctionDeclaration'].includes(nodeType)) { | ||||
|         if (nodeType === 'ImportSpecifier' && (binding.path.parentPath.node as t.ImportDeclaration)?.specifiers.length === 1) { | ||||
|           binding.path.parentPath.remove(); | ||||
|         } else if (nodeType === 'VariableDeclarator') { | ||||
|           if (binding.identifier === binding.path.node.id) { | ||||
|             binding.path.remove(); | ||||
|           } else { | ||||
|             if (binding.path.node.id.type === 'ArrayPattern') { | ||||
|               binding.path.node.id.elements = binding.path.node.id.elements.filter((element) => | ||||
|                 (element !== binding.identifier && (element as t.RestElement)?.argument !== binding.identifier)); | ||||
|               if (binding.path.node.id.elements.length === 0) { | ||||
|                 binding.path.remove(); | ||||
|               } | ||||
|             } else if (binding.path.node.id.type === 'ObjectPattern') { | ||||
|               binding.path.node.id.properties = binding.path.node.id.properties.filter((property) => { | ||||
|                 const { value, key } = property as t.ObjectProperty; | ||||
|                 const argument = (property as t.RestElement)?.argument; | ||||
|                 return value !== binding.identifier && argument !== binding.identifier && | ||||
|                   (key?.type !== 'Identifier' || (key as t.Identifier)?.name !== binding.identifier.name); | ||||
|               }); | ||||
|               if (binding.path.node.id.properties.length === 0) { | ||||
|                 binding.path.remove(); | ||||
|               } | ||||
|             } | ||||
|           } | ||||
|         } else { | ||||
|           binding.path.remove(); | ||||
|         } | ||||
|         hasRemoved = true; | ||||
|       } else if (['ImportDefaultSpecifier'].includes(nodeType)) { | ||||
|         binding.path.parentPath.remove(); | ||||
|         hasRemoved = true; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   if (hasRemoved) { | ||||
|     // Remove code until there is no more to removed.
 | ||||
|     removeUnreferencedCode(nodePath); | ||||
|   } | ||||
| }; | ||||
| 
 | ||||
| const keepExportCode = (identifier: t.Identifier, keepExports: string[]) => { | ||||
|   return keepExports.some((exportString) => { | ||||
|     return t.isIdentifier(identifier, { name: exportString }); | ||||
|   }); | ||||
| }; | ||||
| 
 | ||||
| const removeTopLevelCode = (keepExports: string[] = []) => { | ||||
|   return { | ||||
|     ExportNamedDeclaration: { | ||||
|       enter(nodePath: NodePath<t.ExportNamedDeclaration>) { | ||||
|         const { node } = nodePath; | ||||
|         // Exp: export function pageConfig() {}
 | ||||
|         const isFunctionExport = t.isFunctionDeclaration(node.declaration) && | ||||
|           keepExportCode(node.declaration.id, keepExports); | ||||
|         // Exp: export const pageConfig = () => {}
 | ||||
|         const isVariableExport = t.isVariableDeclaration(node.declaration) && | ||||
|           keepExportCode(node.declaration.declarations![0]?.id as t.Identifier, keepExports); | ||||
|         // Exp: export { pageConfig };
 | ||||
|         if (node.specifiers && node.specifiers.length > 0) { | ||||
|           nodePath.traverse({ | ||||
|             ExportSpecifier(nodePath: NodePath<t.ExportSpecifier>) { | ||||
|               if (!keepExportCode(nodePath.node.exported as t.Identifier, keepExports)) { | ||||
|                 nodePath.remove(); | ||||
|               } | ||||
|             }, | ||||
|           }); | ||||
|           node.specifiers = node.specifiers.filter(specifier => | ||||
|             keepExportCode(specifier.exported as t.Identifier, keepExports)); | ||||
|         } else if (!isFunctionExport && !isVariableExport) { | ||||
|           // Remove named export expect defined in keepExports.
 | ||||
|           nodePath.remove(); | ||||
|         } | ||||
|       }, | ||||
|     }, | ||||
|     ExportDefaultDeclaration: { | ||||
|       enter(nodePath: NodePath<t.ExportDefaultDeclaration>) { | ||||
|         // Remove default export declaration.
 | ||||
|         if (!keepExports.includes('default')) { | ||||
|           nodePath.remove(); | ||||
|         } | ||||
|       }, | ||||
|     }, | ||||
|     ExpressionStatement: { | ||||
|       enter(nodePath: NodePath<t.ExpressionStatement>) { | ||||
|         // Remove top level call expression.
 | ||||
|         if (nodePath.parentPath.isProgram()) { | ||||
|           if (t.isCallExpression(nodePath.node.expression) || t.isAssignmentExpression(nodePath.node.expression)) { | ||||
|             nodePath.remove(); | ||||
|           } | ||||
|         } | ||||
|       }, | ||||
|     }, | ||||
|     ImportDeclaration: { | ||||
|       enter(nodePath: NodePath<t.ImportDeclaration>) { | ||||
|         // Remove import statement without specifiers.
 | ||||
|         if (nodePath.node.specifiers.length === 0) { | ||||
|           nodePath.remove(); | ||||
|         } | ||||
|       }, | ||||
|     }, | ||||
|     'IfStatement|TryStatement|WhileStatement|DoWhileStatement': { | ||||
|       // Remove statement even if it's may cause variable changed.
 | ||||
|       enter(nodePath: NodePath<t.IfStatement | t.TryStatement | t.WhileStatement>) { | ||||
|         // TODO: check expression statement if it is changed top level variable referenced by pageConfig
 | ||||
|         nodePath.remove(); | ||||
|       }, | ||||
|     }, | ||||
|     Program: { | ||||
|       exit(nodePath: NodePath<t.Program>) { | ||||
|         removeUnreferencedCode(nodePath); | ||||
|       }, | ||||
|     }, | ||||
|   }; | ||||
| }; | ||||
| 
 | ||||
| export default removeTopLevelCode; | ||||
|  | @ -1,2 +0,0 @@ | |||
| const a = 1; | ||||
| export default a; | ||||
|  | @ -1,6 +0,0 @@ | |||
| const pageConfig = () => {}; | ||||
| const getData = () => {}; | ||||
| export { | ||||
|   pageConfig, | ||||
|   getData, | ||||
| }; | ||||
|  | @ -1,2 +0,0 @@ | |||
| export const getData = () => {}; | ||||
| export const pageConfig = () => {}; | ||||
|  | @ -1,2 +0,0 @@ | |||
| const a = {}; | ||||
| a.test = 1; | ||||
|  | @ -1,3 +0,0 @@ | |||
| export default function Bar() {} | ||||
| export function pageConfig() {} | ||||
| export function getData() {} | ||||
|  | @ -1,4 +0,0 @@ | |||
| let a = 1; | ||||
| if (true) { | ||||
|   a = 2; | ||||
| } | ||||
|  | @ -1,5 +0,0 @@ | |||
| function a() {} | ||||
| a(); | ||||
| console.log('test', window.a); | ||||
| const b = []; | ||||
| b.map(() => {}); | ||||
|  | @ -1,8 +0,0 @@ | |||
| import { a, b } from 'test'; | ||||
| import { a as c } from 'test-a'; | ||||
| import d from 'test-d'; | ||||
| import 'test-c'; | ||||
| 
 | ||||
| export function pageConfig() { | ||||
|   return { a: 1 }; | ||||
| } | ||||
|  | @ -1,11 +0,0 @@ | |||
| import React, { useState, useEffect } from 'react'; | ||||
| 
 | ||||
| export default function Bar() { | ||||
|   const [str] = useState(''); | ||||
|   useEffect(() => {}, []); | ||||
|   return <React.Fragment>{str}</React.Fragment>; | ||||
| } | ||||
| 
 | ||||
| export function pageConfig() { | ||||
|   return { a: 1 }; | ||||
| } | ||||
|  | @ -1,7 +0,0 @@ | |||
| const c = {}; | ||||
| const { a = '', b = '' } = c; | ||||
| const d = () => { | ||||
|   console.log(a, b); | ||||
| } | ||||
| 
 | ||||
| export default d; | ||||
|  | @ -1,5 +0,0 @@ | |||
| import { a, b } from 'test'; | ||||
| 
 | ||||
| function test() { | ||||
|   a(); | ||||
| } | ||||
|  | @ -1,17 +0,0 @@ | |||
| import { a, z } from 'a'; | ||||
| import b from 'b'; | ||||
| import c from 'c'; | ||||
| import d from 'd'; | ||||
| 
 | ||||
| const [e, f, ...rest] = a; | ||||
| const { h, j } = b; | ||||
| const [x, ...m] = c; | ||||
| const zz = 'x'; | ||||
| const { k, l, ...s } = d; | ||||
| 
 | ||||
| export function pageConfig() { | ||||
|   return { | ||||
|     x, | ||||
|     k, | ||||
|   }; | ||||
| } | ||||
|  | @ -1,8 +0,0 @@ | |||
| let j = 2; | ||||
| let i = 2; | ||||
| while (j < 3) { | ||||
|   j++; | ||||
| } | ||||
| do { | ||||
|   i++; | ||||
| } while (i < 5); | ||||
|  | @ -1,108 +0,0 @@ | |||
| import * as path from 'path'; | ||||
| import * as fs from 'fs'; | ||||
| import { fileURLToPath } from 'url'; | ||||
| import { expect, it, describe } from 'vitest'; | ||||
| import { parse, type ParserOptions } from '@babel/parser'; | ||||
| import traverse from '@babel/traverse'; | ||||
| import generate from '@babel/generator'; | ||||
| import removeTopLevelCodePlugin from '../src/utils/babelPluginRemoveCode'; | ||||
| 
 | ||||
| const __dirname = path.dirname(fileURLToPath(import.meta.url)); | ||||
| 
 | ||||
| const parserOptions: ParserOptions = { | ||||
|   sourceType: 'module', | ||||
|   plugins: [ | ||||
|     'jsx', | ||||
|     'importMeta', | ||||
|     'topLevelAwait', | ||||
|     'classProperties', | ||||
|     'classPrivateMethods', | ||||
|     'typescript', | ||||
|     'decorators-legacy', | ||||
|   ], | ||||
| }; | ||||
| 
 | ||||
| describe('remove top level code', () => { | ||||
|   it('remove specifier export', () => { | ||||
|     const ast = parse(fs.readFileSync(path.join(__dirname, './fixtures/removeCode/export-specifier.ts'), 'utf-8'), parserOptions); | ||||
|     traverse(ast, removeTopLevelCodePlugin(['pageConfig'])); | ||||
|     const content = generate(ast).code; | ||||
|     expect(content.replace(/\n/g, '').replace(/\s+/g, ' ')).toBe('const pageConfig = () => {};export { pageConfig };'); | ||||
|   }); | ||||
|   it('remove variable export', () => { | ||||
|     const ast = parse(fs.readFileSync(path.join(__dirname, './fixtures/removeCode/export-variable.ts'), 'utf-8'), parserOptions); | ||||
|     traverse(ast, removeTopLevelCodePlugin(['pageConfig'])); | ||||
|     const content = generate(ast).code; | ||||
|     expect(content.replace(/\n/g, '').replace(/\s+/g, ' ')).toBe('export const pageConfig = () => {};'); | ||||
|   }); | ||||
|   it('remove function export', () => { | ||||
|     const ast = parse(fs.readFileSync(path.join(__dirname, './fixtures/removeCode/function-exports.ts'), 'utf-8'), parserOptions); | ||||
|     traverse(ast, removeTopLevelCodePlugin(['pageConfig'])); | ||||
|     const content = generate(ast).code; | ||||
|     expect(content.replace(/\n/g, '').replace(/\s+/g, ' ')).toBe('export function pageConfig() {}'); | ||||
|   }); | ||||
|   it('remove if statement', () => { | ||||
|     const ast = parse(fs.readFileSync(path.join(__dirname, './fixtures/removeCode/if.ts'), 'utf-8'), parserOptions); | ||||
|     traverse(ast, removeTopLevelCodePlugin(['pageConfig'])); | ||||
|     const content = generate(ast).code; | ||||
|     expect(content).toBe(''); | ||||
|   }); | ||||
|   it('remove import statement', () => { | ||||
|     const ast = parse(fs.readFileSync(path.join(__dirname, './fixtures/removeCode/import.ts'), 'utf-8'), parserOptions); | ||||
|     traverse(ast, removeTopLevelCodePlugin(['pageConfig'])); | ||||
|     const content = generate(ast).code; | ||||
|     expect(content.replace(/\n/g, '').replace(/\s+/g, ' ')).toBe('export function pageConfig() { return { a: 1 };}'); | ||||
|   }); | ||||
|   it('remove mixed import statement', () => { | ||||
|     const ast = parse(fs.readFileSync(path.join(__dirname, './fixtures/removeCode/mixed-import.tsx'), 'utf-8'), parserOptions); | ||||
|     traverse(ast, removeTopLevelCodePlugin(['pageConfig'])); | ||||
|     const content = generate(ast).code; | ||||
|     expect(content.replace(/\n/g, '').replace(/\s+/g, ' ')).toBe('export function pageConfig() { return { a: 1 };}'); | ||||
|   }); | ||||
|   it('remove IIFE code', () => { | ||||
|     const ast = parse(fs.readFileSync(path.join(__dirname, './fixtures/removeCode/iife.ts'), 'utf-8'), parserOptions); | ||||
|     traverse(ast, removeTopLevelCodePlugin(['pageConfig'])); | ||||
|     const content = generate(ast).code; | ||||
|     expect(content).toBe(''); | ||||
|   }); | ||||
|   it('remove loop code', () => { | ||||
|     const ast = parse(fs.readFileSync(path.join(__dirname, './fixtures/removeCode/while.ts'), 'utf-8'), parserOptions); | ||||
|     traverse(ast, removeTopLevelCodePlugin(['pageConfig'])); | ||||
|     const content = generate(ast).code; | ||||
|     expect(content).toBe(''); | ||||
|   }); | ||||
|   it('remove nested reference code', () => { | ||||
|     const ast = parse(fs.readFileSync(path.join(__dirname, './fixtures/removeCode/reference.ts'), 'utf-8'), parserOptions); | ||||
|     traverse(ast, removeTopLevelCodePlugin(['pageConfig'])); | ||||
|     const content = generate(ast).code; | ||||
|     expect(content).toBe(''); | ||||
|   }); | ||||
| 
 | ||||
|   it('remove variable declaration code', () => { | ||||
|     const ast = parse(fs.readFileSync(path.join(__dirname, './fixtures/removeCode/vars.ts'), 'utf-8'), parserOptions); | ||||
|     traverse(ast, removeTopLevelCodePlugin(['pageConfig'])); | ||||
|     const content = generate(ast).code; | ||||
|     expect(content.replace(/\n/g, '').replace(/\s+/g, ' ')).toBe('import c from \'c\';import d from \'d\';const [x] = c;const { k} = d;export function pageConfig() { return { x, k };}'); | ||||
|   }); | ||||
| 
 | ||||
|   it('keep export default', () => { | ||||
|     const ast = parse(fs.readFileSync(path.join(__dirname, './fixtures/removeCode/export-default.ts'), 'utf-8'), parserOptions); | ||||
|     traverse(ast, removeTopLevelCodePlugin(['default'])); | ||||
|     const content = generate(ast).code; | ||||
|     expect(content.replace(/\n/g, '').replace(/\s+/g, ' ')).toBe('const a = 1;export default a;'); | ||||
|   }); | ||||
| 
 | ||||
|   it('remove expression statement', () => { | ||||
|     const ast = parse(fs.readFileSync(path.join(__dirname, './fixtures/removeCode/expression.ts'), 'utf-8'), parserOptions); | ||||
|     traverse(ast, removeTopLevelCodePlugin(['default'])); | ||||
|     const content = generate(ast).code; | ||||
|     expect(content.replace(/\n/g, '').replace(/\s+/g, ' ')).toBe(''); | ||||
|   }); | ||||
| 
 | ||||
|   it('remove nested reference code', () => { | ||||
|     const ast = parse(fs.readFileSync(path.join(__dirname, './fixtures/removeCode/properties.ts'), 'utf-8'), parserOptions); | ||||
|     traverse(ast, removeTopLevelCodePlugin(['pageConfig'])); | ||||
|     const content = generate(ast).code; | ||||
|     expect(content.replace(/\n/g, '').replace(/\s+/g, ' ')).toBe(''); | ||||
|   }); | ||||
| }); | ||||
|  | @ -39,7 +39,7 @@ type Experimental = Configuration['experiments']; | |||
| interface SwcOptions { | ||||
|   removeExportExprs?: string[]; | ||||
|   compilationConfig?: SwcCompilationConfig | ((source: string, id: string) => SwcCompilationConfig); | ||||
|   keepExports?: string[]; | ||||
|   keepExports?: string[] | { value: string[]; include?: (id: string) => boolean }; | ||||
|   nodeTransform?: boolean; | ||||
| } | ||||
| 
 | ||||
|  |  | |||
|  | @ -114,23 +114,22 @@ const compilationPlugin = (options: Options): UnpluginOptions => { | |||
|           ]); | ||||
|         } | ||||
|       } | ||||
| 
 | ||||
|       if (keepExports) { | ||||
|         if (isRouteEntry(id)) { | ||||
|           swcPlugins.push([ | ||||
|             swcPluginKeepExport, | ||||
|             keepExports, | ||||
|           ]); | ||||
|         } else if (isAppEntry(id)) { | ||||
|           let keepList; | ||||
| 
 | ||||
|           if (keepExports.indexOf('pageConfig') > -1) { | ||||
|             // when build for pageConfig, should keep default, it equals to getAppConfig
 | ||||
|             keepList = keepExports.concat(['default']); | ||||
|         const keepList = Array.isArray(keepExports) ? keepExports : keepExports.value; | ||||
|         const customInlcude = !Array.isArray(keepExports) && keepExports?.include; | ||||
|         let matchRule = false; | ||||
|         if (customInlcude) { | ||||
|           matchRule = customInlcude(id); | ||||
|         } else { | ||||
|             keepList = keepExports; | ||||
|           const matchRoute = isRouteEntry(id); | ||||
|           const matchEntry = isAppEntry(id); | ||||
|           if (matchEntry && keepList.indexOf('pageConfig') > -1) { | ||||
|             // when build for pageConfig, should keep default, it equals to getAppConfig
 | ||||
|             keepList.push('default'); | ||||
|           } | ||||
| 
 | ||||
|           matchRule = matchRoute || matchEntry; | ||||
|         } | ||||
|         if (matchRule) { | ||||
|           swcPlugins.push([ | ||||
|             swcPluginKeepExport, | ||||
|             keepList, | ||||
|  |  | |||
|  | @ -800,7 +800,7 @@ importers: | |||
| 
 | ||||
|   packages/bundles: | ||||
|     specifiers: | ||||
|       '@ice/swc-plugin-keep-export': 0.1.4 | ||||
|       '@ice/swc-plugin-keep-export': 0.1.4-2 | ||||
|       '@ice/swc-plugin-node-transform': 0.1.0-5 | ||||
|       '@ice/swc-plugin-remove-export': 0.1.2 | ||||
|       '@pmmmwh/react-refresh-webpack-plugin': 0.5.10 | ||||
|  | @ -879,7 +879,7 @@ importers: | |||
|       webpack-dev-server: 4.11.1 | ||||
|       ws: ^8.4.2 | ||||
|     dependencies: | ||||
|       '@ice/swc-plugin-keep-export': 0.1.4 | ||||
|       '@ice/swc-plugin-keep-export': 0.1.4-2 | ||||
|       '@ice/swc-plugin-node-transform': 0.1.0-5 | ||||
|       '@ice/swc-plugin-remove-export': 0.1.2 | ||||
|       '@swc/core': 1.3.19 | ||||
|  | @ -980,10 +980,6 @@ importers: | |||
| 
 | ||||
|   packages/ice: | ||||
|     specifiers: | ||||
|       '@babel/generator': 7.18.10 | ||||
|       '@babel/parser': 7.18.10 | ||||
|       '@babel/traverse': 7.18.10 | ||||
|       '@babel/types': 7.18.10 | ||||
|       '@ice/bundles': 0.1.8 | ||||
|       '@ice/route-manifest': 1.1.1 | ||||
|       '@ice/runtime': ^1.1.5 | ||||
|  | @ -1010,7 +1006,6 @@ importers: | |||
|       dotenv-expand: ^8.0.3 | ||||
|       ejs: ^3.1.6 | ||||
|       esbuild: ^0.16.5 | ||||
|       estree-walker: ^3.0.2 | ||||
|       fast-glob: ^3.2.11 | ||||
|       find-up: ^5.0.0 | ||||
|       fs-extra: ^10.0.0 | ||||
|  | @ -1032,10 +1027,6 @@ importers: | |||
|       webpack-dev-server: ^4.7.4 | ||||
|       yargs-parser: ^21.1.1 | ||||
|     dependencies: | ||||
|       '@babel/generator': 7.18.10 | ||||
|       '@babel/parser': 7.18.10 | ||||
|       '@babel/traverse': 7.18.10 | ||||
|       '@babel/types': 7.18.10 | ||||
|       '@ice/bundles': link:../bundles | ||||
|       '@ice/route-manifest': link:../route-manifest | ||||
|       '@ice/runtime': link:../runtime | ||||
|  | @ -1052,7 +1043,6 @@ importers: | |||
|       dotenv: 16.0.3 | ||||
|       dotenv-expand: 8.0.3 | ||||
|       ejs: 3.1.8 | ||||
|       estree-walker: 3.0.3 | ||||
|       fast-glob: 3.2.12 | ||||
|       find-up: 5.0.0 | ||||
|       fs-extra: 10.1.0 | ||||
|  | @ -5187,8 +5177,8 @@ packages: | |||
|       - react-native | ||||
|     dev: false | ||||
| 
 | ||||
|   /@ice/swc-plugin-keep-export/0.1.4: | ||||
|     resolution: {integrity: sha512-fOc09KALmL2zJK1xNGTEt/C27mXL7NVn/v1eRjjuM4uer+qmWIxYXIa9dpfTX5ZUn8zXhrKH8lGdczoKHCzyQQ==} | ||||
|   /@ice/swc-plugin-keep-export/0.1.4-2: | ||||
|     resolution: {integrity: sha512-kmQms1GTc4LBfPK+SyEo3UBBX0GMhPB02VJPA34AtIpNmaWApgmkqQBHbmeeV8ad0nrHrxTfRL80ldMhplyC4g==} | ||||
|     dev: false | ||||
| 
 | ||||
|   /@ice/swc-plugin-node-transform/0.1.0-5: | ||||
|  | @ -11130,12 +11120,6 @@ packages: | |||
|   /estree-walker/2.0.2: | ||||
|     resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} | ||||
| 
 | ||||
|   /estree-walker/3.0.3: | ||||
|     resolution: {integrity: sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==} | ||||
|     dependencies: | ||||
|       '@types/estree': 1.0.0 | ||||
|     dev: false | ||||
| 
 | ||||
|   /esutils/2.0.3: | ||||
|     resolution: {integrity: sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==} | ||||
|     engines: {node: '>=0.10.0'} | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue