Skip to content

Commit

Permalink
feat: support returning source map from transforms
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed Jun 19, 2020
1 parent 4a776f7 commit 3ca09b0
Show file tree
Hide file tree
Showing 9 changed files with 123 additions and 38 deletions.
1 change: 0 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,6 @@
"rollup-plugin-vue": "^6.0.0-beta.6",
"selfsigned": "^1.10.7",
"slash": "^3.0.0",
"source-map": "^0.6.1",
"vue": "^3.0.0-beta.14",
"ws": "^7.2.3"
},
Expand Down
25 changes: 19 additions & 6 deletions playground/plugins/jsPlugin.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,28 @@
import { Plugin } from 'vite'
import MagicString from 'magic-string'

export const jsPlugin: Plugin = {
transforms: [
{
test({ id }) {
return id.endsWith('testTransform.js')
test({ path }) {
return path.endsWith('testTransform.js')
},
transform({ code }) {
return code.replace(/__TEST_TRANSFORM__ = (\d)/, (_, n) => {
return `__TEST_TRANSFORM__ = ${Number(n) + 1}`
})
transform({ id, code }) {
const s = new MagicString(code)

const i = code.indexOf(`=`)
const cur = code.substring(i + 2, i + 3)
s.overwrite(i + 2, i + 3, String(Number(cur) + 1))
// test source map by appending lines
s.prepend(`\n\n\n`)

return {
code: s.toString(),
map: s.generateMap({
source: id,
includeContent: true
})
}
}
}
]
Expand Down
2 changes: 1 addition & 1 deletion src/node/build/buildPluginEsbuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export const createEsbuildPlugin = async (
},

async transform(code, id) {
const isVueTs = /\.vue\?/.test(id) && id.endsWith('lang=ts')
const isVueTs = /\.vue\?/.test(id) && id.endsWith('lang.ts')
if (tjsxRE.test(id) || isVueTs) {
return transform(
code,
Expand Down
6 changes: 4 additions & 2 deletions src/node/esbuildService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import path from 'path'
import chalk from 'chalk'
import { startService, Service, TransformOptions, Message } from 'esbuild'
import { SharedConfig } from './config'
import { cleanUrl } from './utils'

const debug = require('debug')('vite:esbuild')

Expand Down Expand Up @@ -54,16 +55,17 @@ const sourceMapRE = /\/\/# sourceMappingURL.*/
// transform used in server plugins with a more friendly API
export const transform = async (
src: string,
file: string,
request: string,
options: TransformOptions = {},
jsxOption?: SharedConfig['jsx']
) => {
const service = await ensureService()
const file = cleanUrl(request)
options = {
...options,
loader: options.loader || (path.extname(file).slice(1) as any),
sourcemap: true,
sourcefile: file,
sourcefile: request, // ensure source file name contains full query
target: 'es2019'
}
try {
Expand Down
5 changes: 2 additions & 3 deletions src/node/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,7 @@ import { proxyPlugin } from './serverPluginProxy'
import { createCertificate } from '../utils/createCertificate'
import { envPlugin } from './serverPluginEnv'
export { rewriteImports } from './serverPluginModuleRewrite'
import { RawSourceMap } from 'source-map'
import { sourceMapPlugin } from './serverPluginSourceMap'
import { sourceMapPlugin, SourceMap } from './serverPluginSourceMap'

export type ServerPlugin = (ctx: ServerPluginContext) => void

Expand All @@ -40,7 +39,7 @@ export interface State extends DefaultState {}

export type Context = DefaultContext &
ServerPluginContext & {
map?: RawSourceMap | string | null
map?: SourceMap | null
}

export function createServer(config: ServerConfig): Server {
Expand Down
6 changes: 4 additions & 2 deletions src/node/server/serverPluginEsbuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,14 @@ export const esbuildPlugin: ServerPlugin = ({ app, config }) => {
const src = await readBody(ctx.body)
const { code, map } = await transform(
src!,
ctx.path,
ctx.url,
jsxConfig,
config.jsx
)
ctx.body = code
ctx.map = map
if (map) {
ctx.map = JSON.parse(map)
}
}
})
}
26 changes: 24 additions & 2 deletions src/node/server/serverPluginSourceMap.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,29 @@
import { ServerPlugin } from '.'
import { RawSourceMap } from 'source-map'
import merge from 'merge-source-map'

function genSourceMapString(map: RawSourceMap | string | undefined) {
export interface SourceMap {
version: number | string
file: string
sources: string[]
sourcesContent: string[]
names: string[]
mappings: string
}

export function mergeSourceMap(
oldMap: SourceMap | null | undefined,
newMap: SourceMap
): SourceMap {
if (!oldMap) {
return newMap
}
// merge-source-map will overwrite original sources if newMap also has
// sourcesContent
newMap.sourcesContent = []
return merge(oldMap, newMap) as SourceMap
}

function genSourceMapString(map: SourceMap | string | undefined) {
if (typeof map !== 'string') {
map = JSON.stringify(map)
}
Expand Down
15 changes: 7 additions & 8 deletions src/node/server/serverPluginVue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,7 @@ import { codegenCss, compileCss, rewriteCssUrls } from '../utils/cssUtils'
import { parse } from '../utils/babelParse'
import MagicString from 'magic-string'
import { resolveImport } from './serverPluginModuleRewrite'
import merge from 'merge-source-map'
import { RawSourceMap } from 'source-map'
import { SourceMap, mergeSourceMap } from './serverPluginSourceMap'

const debug = require('debug')('vite:sfc')
const getEtag = require('etag')
Expand All @@ -46,7 +45,7 @@ interface CacheEntry {

interface ResultWithMap {
code: string
map: RawSourceMap | null | undefined
map: SourceMap | null | undefined
}

export const vueCache = new LRUCache<string, CacheEntry>({
Expand Down Expand Up @@ -418,10 +417,10 @@ async function compileSFCMain(
loader: 'ts'
})
content = code
descriptor.script.map = merge(
descriptor.script.map!,
descriptor.script.map = mergeSourceMap(
descriptor.script.map as SourceMap,
JSON.parse(map!)
) as RawSourceMap
) as SourceMap & { version: string }
}
// rewrite export default.
// fast path: simple regex replacement to avoid full-blown babel parse.
Expand Down Expand Up @@ -487,7 +486,7 @@ async function compileSFCMain(

const result: ResultWithMap = {
code,
map: descriptor.script && descriptor.script.map
map: descriptor.script && (descriptor.script.map as SourceMap)
}

cached = cached || { styles: [], customs: [] }
Expand Down Expand Up @@ -556,7 +555,7 @@ function compileSFCTemplate(

const result = {
code,
map
map: map as SourceMap
}

cached = cached || { styles: [], customs: [] }
Expand Down
75 changes: 62 additions & 13 deletions src/node/transform.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,22 @@
import { ServerPlugin } from './server'
import { Plugin as RollupPlugin } from 'rollup'
import { parseWithQuery, readBody, isImportRequest } from './utils'
import { SourceMap, mergeSourceMap } from './server/serverPluginSourceMap'

type ParsedQuery = Record<string, string | string[] | undefined>

interface TransformTestContext {
/**
* Full specifier of the transformed module, including query parameters
*/
id: string
/**
* Path without query (use this to check for file extensions)
*/
path: string
/**
* Parsed query object
*/
query: ParsedQuery
/**
* Indicates whether this is a request made by js import(), or natively by
Expand All @@ -19,7 +30,14 @@ export interface TransformContext extends TransformTestContext {
code: string
}

export type TransformFn = (ctx: TransformContext) => string | Promise<string>
export interface TransformResult {
code: string
map?: SourceMap
}

export type TransformFn = (
ctx: TransformContext
) => string | TransformResult | Promise<string | TransformResult>

export interface Transform {
test: (ctx: TransformTestContext) => boolean
Expand All @@ -44,24 +62,33 @@ export function createServerTransformPlugin(
return
}

const { path, query } = ctx
const { url, path, query } = ctx
const isImport = isImportRequest(ctx)
const isBuild = false
let code: string = ''

for (const t of transforms) {
const transformContext: TransformTestContext = {
id: path,
id: url,
path,
query,
isImport,
isBuild
}
if (t.test(transformContext)) {
code = code || (await readBody(ctx.body))!
code = await t.transform({
const result = await t.transform({
...transformContext,
code
})
if (typeof result === 'string') {
code = result
} else {
code = result.code
if (result.map) {
ctx.map = mergeSourceMap(ctx.map, result.map)
}
}
ctx.type = 'js'
ctx.body = code
}
Expand All @@ -75,7 +102,8 @@ export function createServerTransformPlugin(
code = code || (await readBody(ctx.body))!
ctx.body = await t({
code,
id: path,
id: url,
path,
query,
isImport,
isBuild
Expand All @@ -94,19 +122,35 @@ export function createBuildJsTransformPlugin(
name: 'vite:transforms',
async transform(code, id) {
const { path, query } = parseWithQuery(id)
let result: string | Promise<string> = code
let transformed: string = code
let map: SourceMap | null = null

const runTransform = async (t: TransformFn, ctx: TransformContext) => {
const result = await t(ctx)
if (typeof result === 'string') {
transformed = result
} else {
transformed = result.code
if (result.map) {
map = mergeSourceMap(map, result.map)
}
}
}

for (const t of transforms) {
const transformContext: TransformContext = {
code: result,
id: path,
code: transformed,
id,
path,
query,
isImport: true,
isBuild: true
}
if (t.test(transformContext)) {
result = await t.transform(transformContext)
await runTransform(t.transform, transformContext)
}
}

// custom blocks
if (query.vue != null && typeof query.type === 'string') {
const t = customBlockTransforms[query.type]
Expand All @@ -120,16 +164,21 @@ export function createBuildJsTransformPlugin(
normalizedQuery[key] = query[key] as string
}
}
result = await t({
code: result,
id: path,
await runTransform(t, {
code: transformed,
id,
path,
query: normalizedQuery,
isImport: true,
isBuild: true
})
}
}
return result

return {
code: transformed,
map
}
}
}
}

0 comments on commit 3ca09b0

Please sign in to comment.