mirror of https://github.com/alibaba/ice.git
				
				
				
			fix: refactor error handling (#6286)
* fix: refactor error handling * fix: logger * fix: sourcemap * fix: test case * fix: test * fix: add brief error message * fix: changelog and lint
This commit is contained in:
		
							parent
							
								
									abdd49de8d
								
							
						
					
					
						commit
						c70c77379d
					
				|  | @ -0,0 +1,5 @@ | ||||||
|  | --- | ||||||
|  | '@ice/app': patch | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | fix: refactor error handling | ||||||
|  | @ -0,0 +1,5 @@ | ||||||
|  | --- | ||||||
|  | '@ice/webpack-config': patch | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | fix: refactor error handling | ||||||
|  | @ -0,0 +1,5 @@ | ||||||
|  | --- | ||||||
|  | '@ice/bundles': patch | ||||||
|  | --- | ||||||
|  | 
 | ||||||
|  | fix: bump webpack(5.84.1) and webpack-dev-server(4.15.0) | ||||||
|  | @ -24,6 +24,6 @@ | ||||||
|     "@types/react": "^18.0.0", |     "@types/react": "^18.0.0", | ||||||
|     "@types/react-dom": "^18.0.2", |     "@types/react-dom": "^18.0.2", | ||||||
|     "speed-measure-webpack-plugin": "^1.5.0", |     "speed-measure-webpack-plugin": "^1.5.0", | ||||||
|     "webpack": "^5.80.0" |     "webpack": "^5.84.1" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -23,6 +23,6 @@ | ||||||
|     "@types/react": "^18.0.0", |     "@types/react": "^18.0.0", | ||||||
|     "@types/react-dom": "^18.0.2", |     "@types/react-dom": "^18.0.2", | ||||||
|     "speed-measure-webpack-plugin": "^1.5.0", |     "speed-measure-webpack-plugin": "^1.5.0", | ||||||
|     "webpack": "^5.80.0" |     "webpack": "^5.84.1" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -21,6 +21,6 @@ | ||||||
|     "@types/react": "^18.0.0", |     "@types/react": "^18.0.0", | ||||||
|     "@types/react-dom": "^18.0.0", |     "@types/react-dom": "^18.0.0", | ||||||
|     "speed-measure-webpack-plugin": "^1.5.0", |     "speed-measure-webpack-plugin": "^1.5.0", | ||||||
|     "webpack": "^5.80.0" |     "webpack": "^5.84.1" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -24,6 +24,6 @@ | ||||||
|     "@types/react": "^18.0.0", |     "@types/react": "^18.0.0", | ||||||
|     "@types/react-dom": "^18.0.2", |     "@types/react-dom": "^18.0.2", | ||||||
|     "speed-measure-webpack-plugin": "^1.5.0", |     "speed-measure-webpack-plugin": "^1.5.0", | ||||||
|     "webpack": "^5.80.0" |     "webpack": "^5.84.1" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -28,6 +28,6 @@ | ||||||
|     "@types/react-dom": "^18.0.2", |     "@types/react-dom": "^18.0.2", | ||||||
|     "browserslist": "^4.19.3", |     "browserslist": "^4.19.3", | ||||||
|     "speed-measure-webpack-plugin": "^1.5.0", |     "speed-measure-webpack-plugin": "^1.5.0", | ||||||
|     "webpack": "^5.80.0" |     "webpack": "^5.84.1" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -24,6 +24,6 @@ | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@types/react": "^18.0.0", |     "@types/react": "^18.0.0", | ||||||
|     "@types/react-dom": "^18.0.2", |     "@types/react-dom": "^18.0.2", | ||||||
|     "webpack": "^5.80.0" |     "webpack": "^5.84.1" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -26,6 +26,6 @@ | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@types/react": "^18.0.0", |     "@types/react": "^18.0.0", | ||||||
|     "@types/react-dom": "^18.0.2", |     "@types/react-dom": "^18.0.2", | ||||||
|     "webpack": "^5.80.0" |     "webpack": "^5.84.1" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -19,6 +19,6 @@ | ||||||
|     "fs-extra": "^10.0.0", |     "fs-extra": "^10.0.0", | ||||||
|     "@types/react": "^18.0.0", |     "@types/react": "^18.0.0", | ||||||
|     "@types/react-dom": "^18.0.2", |     "@types/react-dom": "^18.0.2", | ||||||
|     "webpack": "^5.73.0" |     "webpack": "^5.84.1" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -19,6 +19,6 @@ | ||||||
|     "@types/react": "^18.0.0", |     "@types/react": "^18.0.0", | ||||||
|     "@types/react-dom": "^18.0.0", |     "@types/react-dom": "^18.0.0", | ||||||
|     "speed-measure-webpack-plugin": "^1.5.0", |     "speed-measure-webpack-plugin": "^1.5.0", | ||||||
|     "webpack": "^5.80.0" |     "webpack": "^5.84.1" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -19,6 +19,6 @@ | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@types/react": "^18.0.0", |     "@types/react": "^18.0.0", | ||||||
|     "@types/react-dom": "^18.0.2", |     "@types/react-dom": "^18.0.2", | ||||||
|     "webpack": "^5.80.0" |     "webpack": "^5.84.1" | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -65,9 +65,9 @@ | ||||||
|     "terser-webpack-plugin": "5.3.5", |     "terser-webpack-plugin": "5.3.5", | ||||||
|     "typescript": "^4.6.4", |     "typescript": "^4.6.4", | ||||||
|     "trusted-cert": "1.1.3", |     "trusted-cert": "1.1.3", | ||||||
|     "webpack": "5.80.0", |     "webpack": "5.84.1", | ||||||
|     "webpack-bundle-analyzer": "4.5.0", |     "webpack-bundle-analyzer": "4.5.0", | ||||||
|     "webpack-dev-server": "4.11.1", |     "webpack-dev-server": "4.15.0", | ||||||
|     "unplugin": "0.9.5", |     "unplugin": "0.9.5", | ||||||
|     "bonjour-service": "^1.0.13", |     "bonjour-service": "^1.0.13", | ||||||
|     "colorette": "^2.0.10", |     "colorette": "^2.0.10", | ||||||
|  |  | ||||||
|  | @ -82,7 +82,7 @@ | ||||||
|     "react-router": "6.11.2", |     "react-router": "6.11.2", | ||||||
|     "sass": "^1.50.0", |     "sass": "^1.50.0", | ||||||
|     "unplugin": "^0.9.0", |     "unplugin": "^0.9.0", | ||||||
|     "webpack": "^5.80.0", |     "webpack": "^5.84.1", | ||||||
|     "webpack-dev-server": "^4.7.4" |     "webpack-dev-server": "^4.7.4" | ||||||
|   }, |   }, | ||||||
|   "peerDependencies": { |   "peerDependencies": { | ||||||
|  |  | ||||||
|  | @ -145,9 +145,9 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt | ||||||
|         delete require.cache[serverEntry]; |         delete require.cache[serverEntry]; | ||||||
|         return await dynamicImport(serverEntry, true); |         return await dynamicImport(serverEntry, true); | ||||||
|       } |       } | ||||||
|     } catch (err) { |     } catch (error) { | ||||||
|       // make error clearly, notice typeof err === 'string'
 |       // make error clearly, notice typeof err === 'string'
 | ||||||
|       logger.error('Excute server entry error:', err); |       logger.error('Execute server entry error:', error); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | @ -397,9 +397,9 @@ async function createService({ rootDir, command, commandArgs }: CreateServiceOpt | ||||||
|             spinner: buildSpinner, |             spinner: buildSpinner, | ||||||
|           }); |           }); | ||||||
|         } |         } | ||||||
|       } catch (err) { |       } catch (error) { | ||||||
|         buildSpinner.stop(); |         buildSpinner.stop(); | ||||||
|         throw err; |         throw error; | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|   }; |   }; | ||||||
|  |  | ||||||
|  | @ -64,7 +64,9 @@ const scanPlugin = (options: Options): Plugin => { | ||||||
|       pkgNameCache.set(resolved, result); |       pkgNameCache.set(resolved, result); | ||||||
|       return result; |       return result; | ||||||
|     } catch (err) { |     } catch (err) { | ||||||
|       logger.error(`cant resolve package of path: ${resolved}`, err); |       logger.error(`Can't resolve package of path: ${resolved}`); | ||||||
|  |       // Scan error doesn't affect the build process.
 | ||||||
|  |       logger.error(err); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  | @ -162,4 +164,4 @@ const scanPlugin = (options: Options): Plugin => { | ||||||
|   }; |   }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export default scanPlugin; | export default scanPlugin; | ||||||
|  |  | ||||||
|  | @ -1,6 +1,4 @@ | ||||||
| import path from 'path'; | import path from 'path'; | ||||||
| import type { TransformOptions } from 'esbuild'; |  | ||||||
| import { esbuild } from '@ice/bundles'; |  | ||||||
| import MagicString from '@ice/bundles/compiled/magic-string/index.js'; | import MagicString from '@ice/bundles/compiled/magic-string/index.js'; | ||||||
| import esModuleLexer from '@ice/bundles/compiled/es-module-lexer/index.js'; | import esModuleLexer from '@ice/bundles/compiled/es-module-lexer/index.js'; | ||||||
| import type { ImportSpecifier } from '@ice/bundles/compiled/es-module-lexer/index.js'; | import type { ImportSpecifier } from '@ice/bundles/compiled/es-module-lexer/index.js'; | ||||||
|  | @ -29,17 +27,10 @@ const transformImportPlugin = (preBundleDepsMetadata: PreBundleDepsMetaData, ser | ||||||
|     transformInclude(id: string) { |     transformInclude(id: string) { | ||||||
|       return /\.(js|jsx|ts|tsx)$/.test(id); |       return /\.(js|jsx|ts|tsx)$/.test(id); | ||||||
|     }, |     }, | ||||||
|     async transform(source: string, id: string) { |     async transform(source: string) { | ||||||
|       await init; |       await init; | ||||||
|       let imports: readonly ImportSpecifier[] = []; |       let imports: readonly ImportSpecifier[] = []; | ||||||
|       // es-module-lexer do not support parse jsx syntax, so we first transform the source by esbuild.
 |       imports = parse(source)[0]; | ||||||
|       const transformed = await transformWithESBuild( |  | ||||||
|         source, |  | ||||||
|         id, |  | ||||||
|       ); |  | ||||||
|       source = transformed.code; |  | ||||||
| 
 |  | ||||||
|       imports = parse(transformed.code)[0]; |  | ||||||
|       const str = new MagicString(source); |       const str = new MagicString(source); | ||||||
|       for (let index = 0; index < imports.length; index++) { |       for (let index = 0; index < imports.length; index++) { | ||||||
|         const { |         const { | ||||||
|  | @ -61,30 +52,4 @@ const transformImportPlugin = (preBundleDepsMetadata: PreBundleDepsMetaData, ser | ||||||
|   }; |   }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // Fork from https://github.com/vitejs/vite/blob/d98c8a710b8f0804120c05e5bd3eb403f17e7b30/packages/vite/src/node/plugins/esbuild.ts#L60
 |  | ||||||
| async function transformWithESBuild( |  | ||||||
|   input: string, |  | ||||||
|   filePath: string, |  | ||||||
|   options: TransformOptions = {}, |  | ||||||
| ) { |  | ||||||
|   let loader = options?.loader as TransformOptions['loader']; |  | ||||||
|   if (!loader) { |  | ||||||
|     const extname = path.extname(filePath).slice(1); |  | ||||||
|     if (extname === 'mjs' || extname === 'cjs' || extname === 'js') { |  | ||||||
|       loader = 'jsx'; |  | ||||||
|     } else { |  | ||||||
|       loader = extname as TransformOptions['loader']; |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   const transformOptions = { |  | ||||||
|     sourcemap: true, |  | ||||||
|     sourcefile: filePath, |  | ||||||
|     ...options, |  | ||||||
|     loader, |  | ||||||
|   } as TransformOptions; |  | ||||||
| 
 |  | ||||||
|   return await esbuild.transform(input, transformOptions); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| export default transformImportPlugin; | export default transformImportPlugin; | ||||||
|  |  | ||||||
|  | @ -36,19 +36,17 @@ function guessLoader(id: string): Loader { | ||||||
|  * but esbuild needs them, we fix the two methods. |  * but esbuild needs them, we fix the two methods. | ||||||
|  */ |  */ | ||||||
| export function fixSourceMap(map: any) { | export function fixSourceMap(map: any) { | ||||||
|   if (!('toString' in map)) { |   Object.defineProperty(map, 'toMapString', { | ||||||
|     Object.defineProperty(map, 'toString', { |     enumerable: false, | ||||||
|       enumerable: false, |     value: function toString() { | ||||||
|       value: function toString() { |       return JSON.stringify(this); | ||||||
|         return JSON.stringify(this); |     }, | ||||||
|       }, |   }); | ||||||
|     }); |  | ||||||
|   } |  | ||||||
|   if (!('toUrl' in map)) { |   if (!('toUrl' in map)) { | ||||||
|     Object.defineProperty(map, 'toUrl', { |     Object.defineProperty(map, 'toUrl', { | ||||||
|       enumerable: false, |       enumerable: false, | ||||||
|       value: function toUrl() { |       value: function toUrl() { | ||||||
|         return `data:application/json;charset=utf-8;base64,${Buffer.from(this.toString()).toString('base64')}`; |         return `data:application/json;charset=utf-8;base64,${Buffer.from(this.toMapString()).toString('base64')}`; | ||||||
|       }, |       }, | ||||||
|     }); |     }); | ||||||
|   } |   } | ||||||
|  | @ -135,13 +133,15 @@ const transformPipe = (options: PluginOptions = {}): Plugin => { | ||||||
|                 sourceCode = result; |                 sourceCode = result; | ||||||
|               } else if (typeof result === 'object' && result !== null) { |               } else if (typeof result === 'object' && result !== null) { | ||||||
|                 sourceCode = result.code; |                 sourceCode = result.code; | ||||||
|                 sourceMap = result.map; |                 sourceMap = typeof result.map === 'string' ? JSON.parse(result.map) : result.map; | ||||||
|               } |               } | ||||||
|             } |             } | ||||||
|             if (sourceMap && typeof sourceMap !== 'string') { |             if (sourceMap && typeof sourceMap !== 'string') { | ||||||
|               if (!sourceMap.sourcesContent || sourceMap.sourcesContent.length === 0) { |               if (!sourceMap.sourcesContent || sourceMap.sourcesContent.length === 0) { | ||||||
|                 sourceMap.sourcesContent = [sourceCode]; |                 sourceMap.sourcesContent = [sourceCode]; | ||||||
|               } |               } | ||||||
|  |               // Use relative path to make sure the source map is correct.
 | ||||||
|  |               sourceMap.sources = [path.relative(resolveDir, id)]; | ||||||
|               sourceMap = fixSourceMap(sourceMap); |               sourceMap = fixSourceMap(sourceMap); | ||||||
|               sourceCode += `\n//# sourceMappingURL=${sourceMap.toUrl()}`; |               sourceCode += `\n//# sourceMappingURL=${sourceMap.toUrl()}`; | ||||||
|             } |             } | ||||||
|  | @ -158,4 +158,4 @@ const transformPipe = (options: PluginOptions = {}): Plugin => { | ||||||
|   }; |   }; | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| export default transformPipe; | export default transformPipe; | ||||||
|  |  | ||||||
|  | @ -83,12 +83,12 @@ function decodeParam(val: any) { | ||||||
|   } |   } | ||||||
|   try { |   try { | ||||||
|     return decodeURIComponent(val); |     return decodeURIComponent(val); | ||||||
|   } catch (err) { |   } catch (error) { | ||||||
|     if (err instanceof URIError) { |     if (error instanceof URIError) { | ||||||
|       err.message = `Failed to decode param ' ${val} '`; |       error.message = `Failed to decode param ' ${val} '`; | ||||||
|       (err as any).status = 400; |       (error as any).status = 400; | ||||||
|       (err as any).statusCode = 400; |       (error as any).statusCode = 400; | ||||||
|     } |     } | ||||||
|     throw err; |     throw error; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -47,7 +47,8 @@ export default function getConfigs(rootDir: string, exclude: string[] = []): Moc | ||||||
|     try { |     try { | ||||||
|       mockModule = require(mockFile); |       mockModule = require(mockFile); | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|       logger.error(`Failed to parse mock file ${mockFile}.\n${error.message}`); |       logger.error(`Failed to parse mock file ${mockFile}`); | ||||||
|  |       logger.error(error); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
|     const config = mockModule.default || mockModule || {}; |     const config = mockModule.default || mockModule || {}; | ||||||
|  |  | ||||||
|  | @ -135,7 +135,7 @@ export async function analyzeImports(files: string[], options: Options) { | ||||||
|         })(); |         })(); | ||||||
|       })); |       })); | ||||||
|     } catch (err) { |     } catch (err) { | ||||||
|       logger.error('[ERROR]', `optimize runtime failed when analyze ${filePath}`); |       logger.briefError(`Optimize runtime failed when analyze ${filePath}`); | ||||||
|       logger.debug(err); |       logger.debug(err); | ||||||
|       throw err; |       throw err; | ||||||
|     } |     } | ||||||
|  | @ -151,8 +151,7 @@ export async function analyzeImports(files: string[], options: Options) { | ||||||
|       })); |       })); | ||||||
|     } |     } | ||||||
|     return importSet; |     return importSet; | ||||||
|   } catch (err) { |   } catch (_) { | ||||||
|     logger.debug(err); |  | ||||||
|     return false; |     return false; | ||||||
|   } |   } | ||||||
| } | } | ||||||
|  | @ -199,8 +198,8 @@ export async function scanImports(entries: string[], options?: ScanOptions) { | ||||||
|     ); |     ); | ||||||
|     logger.debug(`Scan completed in ${(performance.now() - start).toFixed(2)}ms:`, deps); |     logger.debug(`Scan completed in ${(performance.now() - start).toFixed(2)}ms:`, deps); | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     logger.error('Failed to scan module imports.', `\n${error.message}`); |     logger.briefError('Failed to scan module imports.'); | ||||||
|     logger.debug(error.stack); |     logger.debug(error); | ||||||
|   } |   } | ||||||
|   return orderedDependencies(deps); |   return orderedDependencies(deps); | ||||||
| } | } | ||||||
|  | @ -256,8 +255,8 @@ export async function getFileExports(options: FileOptions): Promise<CachedRouteE | ||||||
|         } |         } | ||||||
|       } |       } | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|       logger.error(`Failed to get route ${filePath} exports.`, `\n${error.message}`); |       logger.briefError(`Failed to get route ${filePath} exports.`); | ||||||
|       logger.debug(error.stack); |       logger.debug(error); | ||||||
|       cached = { |       cached = { | ||||||
|         exports: [], |         exports: [], | ||||||
|         hash: fileHash, |         hash: fileHash, | ||||||
|  |  | ||||||
|  | @ -135,11 +135,8 @@ export const getAppExportConfig = (rootDir: string) => { | ||||||
|     transformInclude: (id) => id.includes('src/app') || id.includes('.ice'), |     transformInclude: (id) => id.includes('src/app') || id.includes('.ice'), | ||||||
|     getOutfile, |     getOutfile, | ||||||
|     needRecompile: async (entry, keepExports) => { |     needRecompile: async (entry, keepExports) => { | ||||||
|       let cached = null; |  | ||||||
|       const cachedKey = `app_${keepExports.join('_')}_${process.env.__ICE_VERSION__}`; |       const cachedKey = `app_${keepExports.join('_')}_${process.env.__ICE_VERSION__}`; | ||||||
|       try { |       const cached = await getCache(rootDir, cachedKey); | ||||||
|         cached = await getCache(rootDir, cachedKey); |  | ||||||
|       } catch (err) { } |  | ||||||
|       const fileHash = await getFileHash(appEntry); |       const fileHash = await getFileHash(appEntry); | ||||||
|       if (!cached || fileHash !== cached) { |       if (!cached || fileHash !== cached) { | ||||||
|         await setCache(rootDir, cachedKey, fileHash); |         await setCache(rootDir, cachedKey, fileHash); | ||||||
|  | @ -153,8 +150,8 @@ export const getAppExportConfig = (rootDir: string) => { | ||||||
|     try { |     try { | ||||||
|       return (await config.getConfig(exportNames || ['default', 'defineAppConfig'])) || {}; |       return (await config.getConfig(exportNames || ['default', 'defineAppConfig'])) || {}; | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|       logger.warn('Failed to get app config.', `\n${error.message}`); |       logger.briefError('Failed to get app config.'); | ||||||
|       logger.debug(error.stack); |       logger.debug(error); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  | @ -163,8 +160,8 @@ export const getAppExportConfig = (rootDir: string) => { | ||||||
|       try { |       try { | ||||||
|         config.setCompiler(serverCompiler); |         config.setCompiler(serverCompiler); | ||||||
|       } catch (error) { |       } catch (error) { | ||||||
|         logger.error('Failed to compile app config.', `\n${error.message}`); |         logger.briefError('Failed to compile app config.'); | ||||||
|         logger.debug(error.stack); |         logger.debug(error); | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     getAppConfig, |     getAppConfig, | ||||||
|  | @ -203,15 +200,12 @@ export const getRouteExportConfig = (rootDir: string) => { | ||||||
|     rootDir, |     rootDir, | ||||||
|     getOutfile: getRouteConfigOutfile, |     getOutfile: getRouteConfigOutfile, | ||||||
|     needRecompile: async (entry) => { |     needRecompile: async (entry) => { | ||||||
|       let cached = false; |       const cached = await getCache(rootDir, cachedKey); | ||||||
|       try { |  | ||||||
|         cached = await getCache(rootDir, cachedKey); |  | ||||||
|       } catch (err) { } |  | ||||||
|       if (cached) { |       if (cached) { | ||||||
|         // Always use cached file path while `routes-config` trigger re-compile by webpack plugin.
 |         // Always use cached file path while `routes-config` trigger re-compile by webpack plugin.
 | ||||||
|         return entry; |         return entry; | ||||||
|       } else { |       } else { | ||||||
|         setCache(rootDir, cachedKey, 'true'); |         await setCache(rootDir, cachedKey, 'true'); | ||||||
|         return false; |         return false; | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  | @ -222,16 +216,13 @@ export const getRouteExportConfig = (rootDir: string) => { | ||||||
|     rootDir, |     rootDir, | ||||||
|     getOutfile: getdataLoadersConfigOutfile, |     getOutfile: getdataLoadersConfigOutfile, | ||||||
|     needRecompile: async (entry) => { |     needRecompile: async (entry) => { | ||||||
|       let cached = false; |  | ||||||
|       const cachedKey = `loader_config_file_${process.env.__ICE_VERSION__}`; |       const cachedKey = `loader_config_file_${process.env.__ICE_VERSION__}`; | ||||||
|       try { |       const cached = await getCache(rootDir, cachedKey); | ||||||
|         cached = await getCache(rootDir, cachedKey); |  | ||||||
|       } catch (err) { } |  | ||||||
|       if (cached) { |       if (cached) { | ||||||
|         // Always use cached file path while `routes-config` trigger re-compile by webpack plugin.
 |         // Always use cached file path while `routes-config` trigger re-compile by webpack plugin.
 | ||||||
|         return entry; |         return entry; | ||||||
|       } else { |       } else { | ||||||
|         setCache(rootDir, cachedKey, 'true'); |         await setCache(rootDir, cachedKey, 'true'); | ||||||
|         return false; |         return false; | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|  | @ -259,7 +250,7 @@ export const getRouteExportConfig = (rootDir: string) => { | ||||||
|   const ensureRoutesConfig = async () => { |   const ensureRoutesConfig = async () => { | ||||||
|     const configFile = await routeConfig.getConfigFile(['pageConfig']); |     const configFile = await routeConfig.getConfigFile(['pageConfig']); | ||||||
|     if (!configFile) { |     if (!configFile) { | ||||||
|       setCache(rootDir, cachedKey, ''); |       await setCache(rootDir, cachedKey, ''); | ||||||
|     } |     } | ||||||
|   }; |   }; | ||||||
| 
 | 
 | ||||||
|  | @ -269,14 +260,14 @@ export const getRouteExportConfig = (rootDir: string) => { | ||||||
|       try { |       try { | ||||||
|         routeConfig.setCompiler(serverCompiler); |         routeConfig.setCompiler(serverCompiler); | ||||||
|       } catch (error) { |       } catch (error) { | ||||||
|         routeConfigLogger.error('Failed to get route config.', `\n${error.message}`); |         routeConfigLogger.briefError('Failed to get route config.'); | ||||||
|         routeConfigLogger.debug(error.stack); |         routeConfigLogger.debug(error); | ||||||
|       } |       } | ||||||
|       try { |       try { | ||||||
|         dataloaderConfig.setCompiler(serverCompiler); |         dataloaderConfig.setCompiler(serverCompiler); | ||||||
|       } catch (error) { |       } catch (error) { | ||||||
|         dataLoaderConfigLogger.error('Failed to get dataLoader config.', `\n${error.message}`); |         dataLoaderConfigLogger.briefError('Failed to get dataLoader config.'); | ||||||
|         dataLoaderConfigLogger.debug(error.stack); |         dataLoaderConfigLogger.debug(error); | ||||||
|       } |       } | ||||||
|     }, |     }, | ||||||
|     getRoutesConfig, |     getRoutesConfig, | ||||||
|  |  | ||||||
|  | @ -111,7 +111,7 @@ export default async function preBundleDeps( | ||||||
|       metadata, |       metadata, | ||||||
|     }; |     }; | ||||||
|   } catch (error) { |   } catch (error) { | ||||||
|     logger.error('Failed to bundle dependencies.'); |     logger.briefError('Failed to bundle dependencies.'); | ||||||
|     logger.debug(error); |     logger.debug(error); | ||||||
|     return {}; |     return {}; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  | @ -128,8 +128,7 @@ export function createServerCompiler(options: Options) { | ||||||
|       return (source: string, id: string) => { |       return (source: string, id: string) => { | ||||||
|         return { |         return { | ||||||
|           ...getConfig(source, id), |           ...getConfig(source, id), | ||||||
|           // Force inline when use swc as a transformer.
 |           sourceMaps: !!sourceMap, | ||||||
|           sourceMaps: sourceMap && 'inline', |  | ||||||
|         }; |         }; | ||||||
|       }; |       }; | ||||||
|     } |     } | ||||||
|  | @ -254,13 +253,11 @@ export function createServerCompiler(options: Options) { | ||||||
|         serverEntry, |         serverEntry, | ||||||
|       }; |       }; | ||||||
|     } catch (error) { |     } catch (error) { | ||||||
|       logger.error( |       logger.briefError( | ||||||
|         'Server compiled with errors.', |         'Server compiled with errors.', | ||||||
|         `\nEntryPoints: ${JSON.stringify(buildOptions.entryPoints)}`, |         `\nEntryPoints: ${JSON.stringify(buildOptions.entryPoints)}`, | ||||||
|         `\n${error.message}`, |         `\n${error.message}`, | ||||||
|       ); |       ); | ||||||
|       // TODO: Log esbuild options with namespace.
 |  | ||||||
|       // logger.debug('esbuild options: ', buildOptions);
 |  | ||||||
|       logger.debug(error.stack); |       logger.debug(error.stack); | ||||||
|       return { |       return { | ||||||
|         error: error as Error, |         error: error as Error, | ||||||
|  |  | ||||||
|  | @ -136,7 +136,7 @@ async function webpackCompiler(options: { | ||||||
|   const firstWebpackConfig = webpackConfigs[0]; |   const firstWebpackConfig = webpackConfigs[0]; | ||||||
|   firstWebpackConfig.plugins.push((compiler: webpack.Compiler) => { |   firstWebpackConfig.plugins.push((compiler: webpack.Compiler) => { | ||||||
|     compiler.hooks.beforeCompile.tap('spinner', () => { |     compiler.hooks.beforeCompile.tap('spinner', () => { | ||||||
|       spinner.text = 'compiling...\n'; |       spinner.text = 'Compiling...\n'; | ||||||
|     }); |     }); | ||||||
|     compiler.hooks.afterEmit.tap('spinner', () => { |     compiler.hooks.afterEmit.tap('spinner', () => { | ||||||
|       spinner.stop(); |       spinner.stop(); | ||||||
|  | @ -146,9 +146,9 @@ async function webpackCompiler(options: { | ||||||
|   try { |   try { | ||||||
|     // @ts-ignore
 |     // @ts-ignore
 | ||||||
|     compiler = webpackBundler(webpackConfigs); |     compiler = webpackBundler(webpackConfigs); | ||||||
|   } catch (err) { |   } catch (error) { | ||||||
|     logger.error('Webpack compile error.'); |     logger.error('Webpack compile error.'); | ||||||
|     logger.error(err.message || err); |     logger.error(error); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   let isFirstCompile = true; |   let isFirstCompile = true; | ||||||
|  |  | ||||||
|  | @ -39,9 +39,9 @@ export default async function generateEntry(options: Options): Promise<EntryResu | ||||||
|   let serverEntry; |   let serverEntry; | ||||||
|   try { |   try { | ||||||
|     serverEntry = await dynamicImport(entry); |     serverEntry = await dynamicImport(entry); | ||||||
|   } catch (err) { |   } catch (error) { | ||||||
|     // make error clearly, notice typeof err === 'string'
 |     logger.error(`Error occurred while importing ${entry}`); | ||||||
|     throw new Error(`import ${entry} error: ${err}`); |     throw error; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   // When enable hash-router, only generate one html(index.html).
 |   // When enable hash-router, only generate one html(index.html).
 | ||||||
|  |  | ||||||
|  | @ -1,8 +1,9 @@ | ||||||
| import type { Consola } from 'consola'; | import type { Consola, ConsolaLogObject } from 'consola'; | ||||||
| import consola from 'consola'; | import consola from 'consola'; | ||||||
| 
 | 
 | ||||||
| // In ice.js, we use DEBUG_TAG instead of DEBUG to avoid other libs which use `DEBUG` as their flag log debug info.
 | // In ice.js, we use DEBUG_TAG instead of DEBUG to avoid other libs which use `DEBUG` as their flag log debug info.
 | ||||||
| const { DEBUG_TAG } = process.env; | // eslint-disable-next-line camelcase
 | ||||||
|  | const { DEBUG_TAG, npm_lifecycle_event } = process.env; | ||||||
| 
 | 
 | ||||||
| function getEnableAndDisabledNamespaces(namespaces?: string) { | function getEnableAndDisabledNamespaces(namespaces?: string) { | ||||||
|   const enabledNamespaces: RegExp[] = []; |   const enabledNamespaces: RegExp[] = []; | ||||||
|  | @ -52,22 +53,37 @@ export type CreateLoggerReturnType = Pick<Consola, | | ||||||
|   'ready' | |   'ready' | | ||||||
|   'debug' | |   'debug' | | ||||||
|   'trace' |   'trace' | ||||||
| >; | > & { briefError?: (message: ConsolaLogObject | any, ...args: any[]) => void }; | ||||||
| 
 |  | ||||||
| export type CreateLogger = (namespace?: ICELogNamespace) => CreateLoggerReturnType; | export type CreateLogger = (namespace?: ICELogNamespace) => CreateLoggerReturnType; | ||||||
| 
 | 
 | ||||||
| export const createLogger: CreateLogger = (namespace) => { | export const createLogger: CreateLogger = (namespace) => { | ||||||
|  |   function briefError(message: ConsolaLogObject | any, ...args: any[]) { | ||||||
|  |     consola.error(message, ...args); | ||||||
|  |     if (!DEBUG_TAG) { | ||||||
|  |       // eslint-disable-next-line camelcase
 | ||||||
|  |       consola.log(`run \`DEBUG_TAG=${namespace || '*'} npm run ${npm_lifecycle_event || 'start'}\` to view error details`); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  |   function extendLoggerInstance(instance: Consola): CreateLoggerReturnType { | ||||||
|  |     const logger = {} as CreateLoggerReturnType; | ||||||
|  |     ['fatal', 'error', 'warn', 'log', 'info', 'start', 'success', 'ready', 'debug', 'trace'].forEach((method) => { | ||||||
|  |       logger[method] = instance[method]; | ||||||
|  |     }); | ||||||
|  |     logger.briefError = briefError; | ||||||
|  |     return logger; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|   if (DEBUG_TAG) { |   if (DEBUG_TAG) { | ||||||
|     consola.level = 4; |     consola.level = 4; | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   if (!namespace) { |   if (!namespace) { | ||||||
|     return consola; |     return extendLoggerInstance(consola); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   if (DEBUG_TAG) { |   if (DEBUG_TAG) { | ||||||
|     if (enabled(namespace)) { |     if (enabled(namespace)) { | ||||||
|       return consola.withTag(namespace); |       return extendLoggerInstance(consola.withTag(namespace)); | ||||||
|     } else { |     } else { | ||||||
|       return { |       return { | ||||||
|         fatal() { }, |         fatal() { }, | ||||||
|  | @ -80,10 +96,11 @@ export const createLogger: CreateLogger = (namespace) => { | ||||||
|         ready() { }, |         ready() { }, | ||||||
|         debug() { }, |         debug() { }, | ||||||
|         trace() { }, |         trace() { }, | ||||||
|  |         briefError() {}, | ||||||
|       }; |       }; | ||||||
|     } |     } | ||||||
|   } else { |   } else { | ||||||
|     return consola.withTag(namespace); |     return extendLoggerInstance(consola.withTag(namespace)); | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -154,4 +154,4 @@ function openBrowser(url) { | ||||||
|   } |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export default openBrowser; | export default openBrowser; | ||||||
|  |  | ||||||
|  | @ -3,12 +3,18 @@ import cacache from '@ice/bundles/compiled/cacache/index.js'; | ||||||
| 
 | 
 | ||||||
| const CACHE_PATH = 'node_modules/.cache/route'; | const CACHE_PATH = 'node_modules/.cache/route'; | ||||||
| 
 | 
 | ||||||
| export function getCache(rootDir: string, id: string) { | export async function getCache(rootDir: string, id: string) { | ||||||
|   const cachePath = path.join(rootDir, CACHE_PATH); |   const cachePath = path.join(rootDir, CACHE_PATH); | ||||||
|   return cacache.get(cachePath, id).then((cache) => JSON.parse(cache.data.toString('utf-8'))); |   try { | ||||||
|  |     return await cacache.get(cachePath, id) | ||||||
|  |       .then((cache) => JSON.parse(cache.data.toString('utf-8'))); | ||||||
|  |   } catch (_) { | ||||||
|  |     // Ignore get cache error.
 | ||||||
|  |     return null; | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export function setCache(rootDir: string, id: string, data: any) { | export async function setCache(rootDir: string, id: string, data: any) { | ||||||
|   const cachePath = path.join(rootDir, CACHE_PATH); |   const cachePath = path.join(rootDir, CACHE_PATH); | ||||||
|   return cacache.put(cachePath, id, JSON.stringify(data)); |   return await cacache.put(cachePath, id, JSON.stringify(data)); | ||||||
| } | } | ||||||
|  |  | ||||||
|  | @ -0,0 +1,5 @@ | ||||||
|  | import { defineAppConfig } from '@ice/runtime'; | ||||||
|  | import { getAppConfig } from '@ice/runtime/client'; | ||||||
|  | 
 | ||||||
|  | console.log(getAppConfig); | ||||||
|  | export default defineAppConfig({}); | ||||||
|  | @ -13,7 +13,7 @@ const __dirname = path.dirname(fileURLToPath(import.meta.url)); | ||||||
| const alias = { '@': path.join(__dirname, './fixtures/scan') }; | const alias = { '@': path.join(__dirname, './fixtures/scan') }; | ||||||
| const rootDir = path.join(__dirname, './fixtures/scan'); | const rootDir = path.join(__dirname, './fixtures/scan'); | ||||||
| const cacheDir = path.join(rootDir, '.cache'); | const cacheDir = path.join(rootDir, '.cache'); | ||||||
| const appEntry = path.join(__dirname, './fixtures/scan/app.ts'); | const appEntry = path.join(__dirname, './fixtures/scan/import.js'); | ||||||
| const outdir = path.join(rootDir, 'build'); | const outdir = path.join(rootDir, 'build'); | ||||||
| 
 | 
 | ||||||
| it('transform module import', async () => { | it('transform module import', async () => { | ||||||
|  | @ -35,7 +35,7 @@ it('transform module import', async () => { | ||||||
|       transformImportPlugin(), |       transformImportPlugin(), | ||||||
|     ], |     ], | ||||||
|   }); |   }); | ||||||
|   const buildContent = await fse.readFile(path.join(outdir, 'app.js')); |   const buildContent = await fse.readFile(path.join(outdir, 'import.js'), 'utf-8'); | ||||||
|   expect(buildContent.includes('../../.cache/deps/@ice_runtime_client.mjs')).toBeTruthy(); |   expect(buildContent.includes('../../.cache/deps/@ice_runtime_client.mjs')).toBeTruthy(); | ||||||
|   expect(buildContent.includes('../../.cache/deps/@ice_runtime.mjs')).toBeTruthy(); |   expect(buildContent.includes('../../.cache/deps/@ice_runtime.mjs')).toBeTruthy(); | ||||||
| }); | }); | ||||||
|  |  | ||||||
|  | @ -21,7 +21,7 @@ | ||||||
|     "@ice/bundles": "^0.1.10" |     "@ice/bundles": "^0.1.10" | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "webpack": "^5.80.0" |     "webpack": "^5.84.1" | ||||||
|   }, |   }, | ||||||
|   "publishConfig": { |   "publishConfig": { | ||||||
|     "access": "public" |     "access": "public" | ||||||
|  |  | ||||||
|  | @ -49,7 +49,7 @@ | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@ice/app": "^3.2.0", |     "@ice/app": "^3.2.0", | ||||||
|     "@ice/runtime": "^1.2.0", |     "@ice/runtime": "^1.2.0", | ||||||
|     "webpack": "^5.80.0" |     "webpack": "^5.84.1" | ||||||
|   }, |   }, | ||||||
|   "repository": { |   "repository": { | ||||||
|     "type": "http", |     "type": "http", | ||||||
|  |  | ||||||
|  | @ -28,7 +28,7 @@ | ||||||
|     "@ice/app": "^3.2.0", |     "@ice/app": "^3.2.0", | ||||||
|     "build-scripts": "^2.1.1-0", |     "build-scripts": "^2.1.1-0", | ||||||
|     "esbuild": "^0.17.16", |     "esbuild": "^0.17.16", | ||||||
|     "webpack": "^5.80.0", |     "webpack": "^5.84.1", | ||||||
|     "webpack-dev-server": "^4.9.2" |     "webpack-dev-server": "^4.9.2" | ||||||
|   }, |   }, | ||||||
|   "repository": { |   "repository": { | ||||||
|  |  | ||||||
|  | @ -62,7 +62,7 @@ export default async function generateManifest({ | ||||||
|     // dataLoader may have side effect code.
 |     // dataLoader may have side effect code.
 | ||||||
|     dataloaderConfig = await getDataloaderConfig(); |     dataloaderConfig = await getDataloaderConfig(); | ||||||
|   } catch (err) { |   } catch (err) { | ||||||
|     logger.debug('GetDataloaderConfig failed.'); |     logger.briefError('GetDataloaderConfig failed.'); | ||||||
|     logger.debug(err); |     logger.debug(err); | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -38,7 +38,7 @@ const createPHAMiddleware = ({ | ||||||
|         // dataLoader may have side effect code.
 |         // dataLoader may have side effect code.
 | ||||||
|         dataloaderConfig = await getDataloaderConfig(); |         dataloaderConfig = await getDataloaderConfig(); | ||||||
|       } catch (err) { |       } catch (err) { | ||||||
|         logger.debug('GetDataloaderConfig failed.'); |         logger.briefError('GetDataloaderConfig failed.'); | ||||||
|         logger.debug(err); |         logger.debug(err); | ||||||
|       } |       } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -31,7 +31,7 @@ | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@ice/app": "^3.2.1", |     "@ice/app": "^3.2.1", | ||||||
|     "webpack": "^5.80.0" |     "webpack": "^5.84.1" | ||||||
|   }, |   }, | ||||||
|   "repository": { |   "repository": { | ||||||
|     "type": "http", |     "type": "http", | ||||||
|  |  | ||||||
|  | @ -26,7 +26,7 @@ | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "esbuild": "^0.17.16", |     "esbuild": "^0.17.16", | ||||||
|     "postcss": "^8.4.18", |     "postcss": "^8.4.18", | ||||||
|     "webpack": "^5.80.0", |     "webpack": "^5.84.1", | ||||||
|     "webpack-dev-server": "^4.7.4" |     "webpack-dev-server": "^4.7.4" | ||||||
|   }, |   }, | ||||||
|   "scripts": { |   "scripts": { | ||||||
|  |  | ||||||
|  | @ -94,8 +94,9 @@ export async function redirectImport(code: string, options: Options): Promise<st | ||||||
|   let imports: readonly ImportSpecifier[] = []; |   let imports: readonly ImportSpecifier[] = []; | ||||||
|   try { |   try { | ||||||
|     imports = parse(code)[0]; |     imports = parse(code)[0]; | ||||||
|   } catch (e) { |   } catch (error) { | ||||||
|     consola.debug('[parse error]', e); |     consola.error('Parse error when redirect import.'); | ||||||
|  |     consola.error(error); | ||||||
|   } |   } | ||||||
|   if (!imports.length) { |   if (!imports.length) { | ||||||
|     return code; |     return code; | ||||||
|  |  | ||||||
|  | @ -16,7 +16,7 @@ | ||||||
|   }, |   }, | ||||||
|   "devDependencies": { |   "devDependencies": { | ||||||
|     "@ice/webpack-config": "^1.0.0", |     "@ice/webpack-config": "^1.0.0", | ||||||
|     "webpack": "^5.80.0" |     "webpack": "^5.84.1" | ||||||
|   }, |   }, | ||||||
|   "scripts": { |   "scripts": { | ||||||
|     "watch": "tsc -w", |     "watch": "tsc -w", | ||||||
|  |  | ||||||
							
								
								
									
										414
									
								
								pnpm-lock.yaml
								
								
								
								
							
							
						
						
									
										414
									
								
								pnpm-lock.yaml
								
								
								
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							|  | @ -36,7 +36,7 @@ | ||||||
|     "glob": "^7.2.3", |     "glob": "^7.2.3", | ||||||
|     "gray-matter": "^4.0.3", |     "gray-matter": "^4.0.3", | ||||||
|     "typescript": "^4.9.5", |     "typescript": "^4.9.5", | ||||||
|     "webpack": "^5.80.0" |     "webpack": "^5.84.1" | ||||||
|   }, |   }, | ||||||
|   "browserslist": { |   "browserslist": { | ||||||
|     "production": [ |     "production": [ | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue