From 16001d9c7b59bd105062162825d89429c3c7e7ff Mon Sep 17 00:00:00 2001 From: fxy060608 Date: Fri, 31 Dec 2021 17:22:02 +0800 Subject: [PATCH] feat(mp): souremap (#3138) --- .../uni-app-plus/dist/uni-app-service.es.js | 2 +- packages/uni-app-vite/src/plugin/build.ts | 8 ++- packages/uni-app-vite/src/plugin/index.ts | 4 +- .../__tests__/usingComponents.spec.ts | 10 +++- .../uni-cli-shared/src/mp/usingComponents.ts | 20 ++++++- packages/uni-mp-compiler/package.json | 3 +- packages/uni-mp-compiler/src/codegen.ts | 56 ++++++++++++++++++- packages/uni-mp-compiler/src/options.ts | 1 + packages/uni-mp-vite/src/plugins/mainJs.ts | 9 ++- .../uni-mp-vite/src/plugins/manifestJson.ts | 2 +- packages/uni-mp-vite/src/plugins/pagesJson.ts | 4 +- packages/uni-mp-vite/src/plugins/renderjs.ts | 16 +++--- .../uni-mp-vite/src/plugins/runtimeHooks.ts | 5 +- .../src/plugins/usingComponents.ts | 22 ++++++-- pnpm-lock.yaml | 2 + 15 files changed, 133 insertions(+), 31 deletions(-) diff --git a/packages/uni-app-plus/dist/uni-app-service.es.js b/packages/uni-app-plus/dist/uni-app-service.es.js index 7bdfd425b..35633fb04 100644 --- a/packages/uni-app-plus/dist/uni-app-service.es.js +++ b/packages/uni-app-plus/dist/uni-app-service.es.js @@ -14966,7 +14966,7 @@ var serviceContext = (function (vue) { if (withArrayBuffer) { stream.fetchWithArrayBuffer({ '@type': 'binary', - base64: arrayBufferToBase64(data) + base64: arrayBufferToBase64(data), }, options, callback); } else { diff --git a/packages/uni-app-vite/src/plugin/build.ts b/packages/uni-app-vite/src/plugin/build.ts index 77e13a0e4..8577b46de 100644 --- a/packages/uni-app-vite/src/plugin/build.ts +++ b/packages/uni-app-vite/src/plugin/build.ts @@ -9,7 +9,10 @@ import { APP_SERVICE_FILENAME, } from '@dcloudio/uni-cli-shared' -export function buildOptions(configEnv: ConfigEnv): UserConfig['build'] { +export function buildOptions( + userConfig: UserConfig, + _: ConfigEnv +): UserConfig['build'] { const inputDir = process.env.UNI_INPUT_DIR const outputDir = process.env.UNI_OUTPUT_DIR // 开始编译时,清空输出目录 @@ -17,7 +20,8 @@ export function buildOptions(configEnv: ConfigEnv): UserConfig['build'] { emptyDir(outputDir) } return { - // sourcemap: 'inline', + // App 端目前仅提供 inline + sourcemap: userConfig.build?.sourcemap ? 'inline' : false, emptyOutDir: false, // 不清空输出目录,否则会影响 webpack 的输出 assetsInlineLimit: 0, rollupOptions: { diff --git a/packages/uni-app-vite/src/plugin/index.ts b/packages/uni-app-vite/src/plugin/index.ts index 2e1f1b129..1c8413381 100644 --- a/packages/uni-app-vite/src/plugin/index.ts +++ b/packages/uni-app-vite/src/plugin/index.ts @@ -8,9 +8,9 @@ export function uniAppPlugin(): UniVitePlugin { return { name: 'vite:uni-app', uni: uniOptions(), - config(_, env) { + config(config, env) { return { - build: buildOptions(env), + build: buildOptions(config, env), } }, configResolved, diff --git a/packages/uni-cli-shared/__tests__/usingComponents.spec.ts b/packages/uni-cli-shared/__tests__/usingComponents.spec.ts index 36eadae1c..d8ac75ee8 100644 --- a/packages/uni-cli-shared/__tests__/usingComponents.spec.ts +++ b/packages/uni-cli-shared/__tests__/usingComponents.spec.ts @@ -52,7 +52,9 @@ export function createApp() { 'component-b': '/components/component-b', }) expect(imports.length).toBe(2) - const code = await transformDynamicImports(source, imports, dynamicImport) + const { code } = await transformDynamicImports(source, imports, { + dynamicImport, + }) expect(code).toContain(`import App from './App.vue'`) expect(code).toContain( `const ComponentA = ()=>import('${inputDir}/components/component-a.vue')` @@ -94,7 +96,9 @@ export function createApp() { 'component-b': '/components/component-b', }) expect(imports.length).toBe(2) - const code = await transformDynamicImports(source, imports, dynamicImport) + const { code } = await transformDynamicImports(source, imports, { + dynamicImport, + }) expect(code).toContain(`import App from './App.vue'`) expect(code).toContain( `const ComponentA = ()=>import('${inputDir}/components/component-a.vue')` @@ -119,7 +123,7 @@ export function createApp() { usingComponents ) expect( - await transformDynamicImports(source, imports, dynamicImport) + (await transformDynamicImports(source, imports, { dynamicImport })).code ).toContain(code) } diff --git a/packages/uni-cli-shared/src/mp/usingComponents.ts b/packages/uni-cli-shared/src/mp/usingComponents.ts index 9c7f2f983..c0cef8269 100644 --- a/packages/uni-cli-shared/src/mp/usingComponents.ts +++ b/packages/uni-cli-shared/src/mp/usingComponents.ts @@ -567,10 +567,21 @@ async function parseVueComponentImports( export async function transformDynamicImports( code: string, imports: ImportDeclaration[], - dynamicImport: (name: string, source: string) => string + { + id, + sourceMap, + dynamicImport, + }: { + id?: string + sourceMap?: boolean + dynamicImport: (name: string, source: string) => string + } ) { if (!imports.length) { - return code + return { + code, + map: null, + } } const s = new MagicString(code) for (let i = 0; i < imports.length; i++) { @@ -586,5 +597,8 @@ export async function transformDynamicImports( dynamicImport(specifier.local.name, source.value) + ';' ) } - return s.toString() + return { + code: s.toString(), + map: null, + } } diff --git a/packages/uni-mp-compiler/package.json b/packages/uni-mp-compiler/package.json index 0719c662d..54b30b6ad 100644 --- a/packages/uni-mp-compiler/package.json +++ b/packages/uni-mp-compiler/package.json @@ -30,6 +30,7 @@ "estree-walker": "^2.0.2" }, "devDependencies": { - "@vue/compiler-sfc": "3.2.26" + "@vue/compiler-sfc": "3.2.26", + "source-map": "^0.6.1" } } diff --git a/packages/uni-mp-compiler/src/codegen.ts b/packages/uni-mp-compiler/src/codegen.ts index 3e9f8127d..02a8bfe1f 100644 --- a/packages/uni-mp-compiler/src/codegen.ts +++ b/packages/uni-mp-compiler/src/codegen.ts @@ -1,10 +1,14 @@ import { isString, isSymbol, hasOwn } from '@vue/shared' import { + advancePositionWithMutation, CodegenResult, CompoundExpressionNode, helperNameMap, InterpolationNode, + isSimpleIdentifier, + locStub, NodeTypes, + Position, RESOLVE_COMPONENT, RootNode, SimpleExpressionNode, @@ -14,6 +18,7 @@ import { import { Expression } from '@babel/types' import { default as babelGenerate, GeneratorOptions } from '@babel/generator' import { addImportDeclaration, matchEasycom } from '@dcloudio/uni-cli-shared' +import { SourceMapGenerator } from 'source-map' import { CodegenOptions, CodegenRootNode } from './options' import { @@ -24,8 +29,13 @@ import { interface CodegenContext extends Omit { code: string + source: string + line: number + column: number + offset: number bindingComponents: TransformContext['bindingComponents'] indentLevel: number + map?: SourceMapGenerator push(code: string, node?: CodegenNode): void indent(): void deindent(withoutNewLine?: boolean): void @@ -99,6 +109,8 @@ export function generate( return { code: context.code, preamble: isSetupInlined ? preambleContext.code : ``, + // SourceMapGenerator does have toJSON() method but it's not in the types + map: context.map ? (context.map as any).toJSON() : undefined, } } @@ -112,6 +124,7 @@ function createCodegenContext( runtimeGlobalName = `Vue`, runtimeModuleName = `vue`, isTS = false, + sourceMap = false, }: CodegenOptions ): CodegenContext { const context: CodegenContext = { @@ -123,10 +136,30 @@ function createCodegenContext( runtimeModuleName, bindingComponents: ast.bindingComponents, isTS, + source: ast.loc.source, code: ``, + column: 1, + line: 1, + offset: 0, indentLevel: 0, push(code, node) { context.code += code + if (context.map) { + if (node) { + let name + if (node.type === NodeTypes.SIMPLE_EXPRESSION && !node.isStatic) { + const content = node.content.replace(/^_ctx\./, '') + if (content !== node.content && isSimpleIdentifier(content)) { + name = content + } + } + addMapping(node.loc.start, name) + } + advancePositionWithMutation(context, code) + if (node && node.loc !== locStub) { + addMapping(node.loc.end) + } + } }, indent() { newline(++context.indentLevel) @@ -147,6 +180,27 @@ function createCodegenContext( context.push('\n' + ` `.repeat(n)) } + function addMapping(loc: Position, name?: string) { + context.map!.addMapping({ + name, + source: context.filename || '', + original: { + line: loc.line, + column: loc.column - 1, // source-map column is 0 based + }, + generated: { + line: context.line, + column: context.column - 1, + }, + }) + } + // 暂时无需提供 sourcemap 支持 + // if (sourceMap) { + // // lazy require source-map implementation + // context.map = new SourceMapGenerator() + // context.map!.setSourceContent(filename, context.source) + // } + return context } @@ -282,8 +336,6 @@ type CodegenNode = | CompoundExpressionNode | InterpolationNode | TextNode - | string - | symbol interface GenNodeContext { code: string diff --git a/packages/uni-mp-compiler/src/options.ts b/packages/uni-mp-compiler/src/options.ts index d6acb7c4b..10d18738c 100644 --- a/packages/uni-mp-compiler/src/options.ts +++ b/packages/uni-mp-compiler/src/options.ts @@ -92,6 +92,7 @@ export type CodegenScope = CodegenRootScope | CodegenVIfScope | CodegenVForScope export interface CodegenOptions extends SharedTransformCodegenOptions { mode?: 'module' | 'function' scopeId?: string | null + sourceMap?: boolean runtimeModuleName?: string runtimeGlobalName?: string generatorOpts?: GeneratorOptions diff --git a/packages/uni-mp-vite/src/plugins/mainJs.ts b/packages/uni-mp-vite/src/plugins/mainJs.ts index 2780eca1b..5407ac88b 100644 --- a/packages/uni-mp-vite/src/plugins/mainJs.ts +++ b/packages/uni-mp-vite/src/plugins/mainJs.ts @@ -31,11 +31,16 @@ export function uniMainJsPlugin( resolve: this.resolve, } ) + const { code, map } = await transformDynamicImports(source, imports, { + id, + sourceMap: !!opts.resolvedConfig.build.sourcemap, + dynamicImport, + }) return { code: `import 'plugin-vue:export-helper';import 'uni-mp-runtime';import './pages.json.js';` + - (await transformDynamicImports(source, imports, dynamicImport)), - map: this.getCombinedSourcemap(), + code, + map, } } }, diff --git a/packages/uni-mp-vite/src/plugins/manifestJson.ts b/packages/uni-mp-vite/src/plugins/manifestJson.ts index 1b8fdedc7..9a7294190 100644 --- a/packages/uni-mp-vite/src/plugins/manifestJson.ts +++ b/packages/uni-mp-vite/src/plugins/manifestJson.ts @@ -54,7 +54,7 @@ export function uniManifestJsonPlugin( return { code: '', - map: this.getCombinedSourcemap(), + map: { mappings: '' }, } }, generateBundle() { diff --git a/packages/uni-mp-vite/src/plugins/pagesJson.ts b/packages/uni-mp-vite/src/plugins/pagesJson.ts index 5df8c295c..ac65757a1 100644 --- a/packages/uni-mp-vite/src/plugins/pagesJson.ts +++ b/packages/uni-mp-vite/src/plugins/pagesJson.ts @@ -37,7 +37,7 @@ export function uniPagesJsonPlugin( }, transform(code, id) { if (!opts.filter(id)) { - return + return null } const inputDir = process.env.UNI_INPUT_DIR this.addWatchFile(path.resolve(inputDir, 'pages.json')) @@ -74,7 +74,7 @@ export function uniPagesJsonPlugin( }) return { code: `import './manifest.json.js'\n` + importPagesCode(appJson), - map: this.getCombinedSourcemap(), + map: { mappings: '' }, } }, generateBundle() { diff --git a/packages/uni-mp-vite/src/plugins/renderjs.ts b/packages/uni-mp-vite/src/plugins/renderjs.ts index ae2eca59c..509055642 100644 --- a/packages/uni-mp-vite/src/plugins/renderjs.ts +++ b/packages/uni-mp-vite/src/plugins/renderjs.ts @@ -16,10 +16,6 @@ export function getFiltersCache(resolvedConfig: ResolvedConfig) { return filtersCache.get(resolvedConfig) || [] } -const defaultCode = { - code: 'export default {}', -} - export function uniRenderjsPlugin({ lang }: { lang?: string }): Plugin { let resolvedConfig: ResolvedConfig return { @@ -33,11 +29,14 @@ export function uniRenderjsPlugin({ lang }: { lang?: string }): Plugin { transform(code, id) { const { type, name } = parseRenderjs(id) if (!type) { - return + return null } debugRenderjs(id) if (type !== lang) { - return defaultCode + return { + code: 'export default {}', + map: { mappings: '' }, + } } this.addWatchFile(cleanUrl(id)) if (!name) { @@ -50,7 +49,10 @@ export function uniRenderjsPlugin({ lang }: { lang?: string }): Plugin { code, }) } - return defaultCode + return { + code: 'export default {}', + map: { mappings: '' }, + } }, } } diff --git a/packages/uni-mp-vite/src/plugins/runtimeHooks.ts b/packages/uni-mp-vite/src/plugins/runtimeHooks.ts index 8413e74b9..e9178b7da 100644 --- a/packages/uni-mp-vite/src/plugins/runtimeHooks.ts +++ b/packages/uni-mp-vite/src/plugins/runtimeHooks.ts @@ -33,7 +33,10 @@ export function uniRuntimeHooksPlugin(): Plugin { for (const hook of hooks) { flag |= MINI_PROGRAM_PAGE_RUNTIME_HOOKS[hook] } - return source + `;_sfc_main.__runtimeHooks = ${flag};` + return { + code: source + `;_sfc_main.__runtimeHooks = ${flag};`, + map: { mappings: '' }, + } }, } } diff --git a/packages/uni-mp-vite/src/plugins/usingComponents.ts b/packages/uni-mp-vite/src/plugins/usingComponents.ts index 773af0742..8a8754185 100644 --- a/packages/uni-mp-vite/src/plugins/usingComponents.ts +++ b/packages/uni-mp-vite/src/plugins/usingComponents.ts @@ -1,5 +1,5 @@ import path from 'path' -import type { Plugin } from 'vite' +import type { Plugin, ResolvedConfig } from 'vite' import type { SFCScriptCompileOptions } from '@vue/compiler-sfc' import { EXTNAME_VUE, @@ -25,14 +25,24 @@ export function uniUsingComponentsPlugin( }) } const inputDir = process.env.UNI_INPUT_DIR + let resolvedConfig: ResolvedConfig return { name: 'vite:uni-mp-using-component', enforce: 'post', + configResolved(config) { + resolvedConfig = config + }, async transform(source, id) { const { filename, query } = parseVueRequest(id) if (filename.endsWith('App.vue')) { return null } + const sourceMap = !!resolvedConfig.build.sourcemap + const dynamicImportOptions = { + id, + sourceMap, + dynamicImport, + } if (query.vue) { if (query.type === 'script') { // 需要主动监听 @@ -49,7 +59,7 @@ export function uniUsingComponentsPlugin( return transformDynamicImports( source, descriptor.imports, - dynamicImport + dynamicImportOptions ) } else if (query.type === 'template') { // 需要主动监听 @@ -66,7 +76,7 @@ export function uniUsingComponentsPlugin( return transformDynamicImports( source, descriptor.imports, - dynamicImport + dynamicImportOptions ) } return null @@ -81,7 +91,11 @@ export function uniUsingComponentsPlugin( updateMiniProgramComponentsByMainFilename(filename, inputDir) - return transformDynamicImports(source, descriptor.imports, dynamicImport) + return transformDynamicImports( + source, + descriptor.imports, + dynamicImportOptions + ) }, } } diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index ba3a91dea..0b41bf7d2 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -597,6 +597,7 @@ importers: '@vue/compiler-sfc': 3.2.26 '@vue/shared': 3.2.26 estree-walker: ^2.0.2 + source-map: ^0.6.1 dependencies: '@babel/generator': 7.16.0 '@babel/parser': 7.16.4 @@ -609,6 +610,7 @@ importers: estree-walker: 2.0.2 devDependencies: '@vue/compiler-sfc': 3.2.26 + source-map: 0.6.1 packages/uni-mp-core: specifiers: {} -- GitLab