Skip to content

Commit

Permalink
feat: dev support for ts
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed May 6, 2020
1 parent 4fd2cdf commit 7cbaf5d
Show file tree
Hide file tree
Showing 5 changed files with 120 additions and 30 deletions.
30 changes: 28 additions & 2 deletions src/node/esbuildService.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,33 @@
import { startService, Service, TransformOptions } from 'esbuild'
import { Plugin } from 'rollup'

const transform = async (
// Note: when the esbuild service is held in a module level variable, it
// somehow prevents the build process from exiting even after explicitly
// calling service.stop(). Therefore make sure to only use `ensureService`
// in server plugins. Build plugins should contain the service in its creation
// closure and close it in `generateBundle`.

// lazy start the service
let _service: Service | undefined

const ensureService = async () => {
if (!_service) {
_service = await startService()
}
return _service
}

// transform used in server plugins with a more friendly API
export const transform = async (
code: string,
options: TransformOptions,
operation: string
) => {
return _transform(await ensureService(), code, options, operation)
}

// trasnform that takes the service via arguments, used in build plugins
const _transform = async (
service: Service,
code: string,
options: TransformOptions,
Expand Down Expand Up @@ -33,7 +59,7 @@ export const createMinifyPlugin = async (): Promise<Plugin> => {
return {
name: 'vite:minify',
async renderChunk(code, chunk) {
return transform(
return _transform(
service,
code,
{ minify: true },
Expand Down
38 changes: 28 additions & 10 deletions src/node/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { hmrPlugin, HMRWatcher } from './serverPluginHmr'
import { serveStaticPlugin } from './serverPluginServeStatic'
import { jsonPlugin } from './serverPluginJson'
import { cssPlugin } from './serverPluginCss'
import { esbuildPlugin } from './serverPluginEsbuild'

export { Resolver }

Expand All @@ -20,42 +21,59 @@ export interface PluginContext {
server: Server
watcher: HMRWatcher
resolver: InternalResolver
jsxConfig: {
jsxFactory: string | undefined
jsxFragment: string | undefined
}
}

export interface ServerConfig {
root?: string
plugins?: Plugin[]
resolvers?: Resolver[]
jsx?: {
factory?: string
fragment?: string
}
}

const internalPlugins: Plugin[] = [
moduleRewritePlugin,
moduleResolvePlugin,
vuePlugin,
esbuildPlugin,
jsonPlugin,
cssPlugin,
hmrPlugin,
serveStaticPlugin
]

export function createServer(config: ServerConfig = {}): Server {
const { root = process.cwd(), plugins = [], resolvers = [] } = config
const {
root = process.cwd(),
plugins = [],
resolvers = [],
jsx = {}
} = config
const app = new Koa()
const server = http.createServer(app.callback())
const watcher = chokidar.watch(root, {
ignored: [/node_modules/]
}) as HMRWatcher
const resolver = createResolver(root, resolvers)
const context = {
root,
app,
server,
watcher,
resolver,
jsxConfig: {
jsxFactory: jsx.factory,
jsxFragment: jsx.fragment
}
}

;[...plugins, ...internalPlugins].forEach((m) =>
m({
root,
app,
server,
watcher,
resolver
})
)
;[...plugins, ...internalPlugins].forEach((m) => m(context))

return server
}
39 changes: 39 additions & 0 deletions src/node/serverPluginEsbuild.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
import { Plugin } from './server'
import { readBody, isImportRequest, genSourceMapString } from './utils'
import { TransformOptions } from 'esbuild'
import { transform } from './esbuildService'

const testRE = /\.(tsx?|jsx)$/

export const esbuildPlugin: Plugin = ({ app, watcher, jsxConfig }) => {
app.use(async (ctx, next) => {
await next()
if (isImportRequest(ctx) && ctx.body && testRE.test(ctx.path)) {
ctx.type = 'js'
let options: TransformOptions = {}
if (ctx.path.endsWith('.ts')) {
options = { loader: 'ts' }
} else if (ctx.path.endsWith('tsx')) {
options = { loader: 'tsx', ...jsxConfig }
} else if (ctx.path.endsWith('jsx')) {
options = { loader: 'jsx', ...jsxConfig }
}
const src = await readBody(ctx.body)
const { code, map } = await transform(
src!,
options,
`transpiling ${ctx.path}`
)
ctx.body = code
if (map) {
ctx.body += genSourceMapString(map)
}
}
})

watcher.on('change', (file) => {
if (testRE.test(file)) {
watcher.handleJSReload(file)
}
})
}
31 changes: 13 additions & 18 deletions src/node/serverPluginVue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,10 @@ import hash_sum from 'hash-sum'
import LRUCache from 'lru-cache'
import { hmrClientId } from './serverPluginHmr'
import resolve from 'resolve-from'
import { cachedRead } from './utils'
import { cachedRead, genSourceMapString } from './utils'
import { loadPostcssConfig } from './config'
import { Context } from 'koa'
import { transform } from './esbuildService'

const debug = require('debug')('vite:sfc')
const getEtag = require('etag')
Expand Down Expand Up @@ -54,7 +55,7 @@ export const vuePlugin: Plugin = ({ root, app, resolver }) => {

if (!query.type) {
ctx.type = 'js'
ctx.body = compileSFCMain(descriptor, filePath, publicPath)
ctx.body = await compileSFCMain(descriptor, filePath, publicPath)
return etagCacheCheck(ctx)
}

Expand Down Expand Up @@ -138,23 +139,26 @@ export async function parseSFC(
return descriptor
}

function compileSFCMain(
async function compileSFCMain(
descriptor: SFCDescriptor,
filePath: string,
publicPath: string
): string {
): Promise<string> {
let cached = vueCache.get(filePath)
if (cached && cached.script) {
return cached.script
}

// inject hmr client
let code = ''
if (descriptor.script) {
code += descriptor.script.content.replace(
`export default`,
'const __script ='
)
let content = descriptor.script.content
if (descriptor.script.lang === 'ts') {
content = (
await transform(content, { loader: 'ts' }, `transpiling ${publicPath}`)
).code
}

code += content.replace(`export default`, 'const __script =')
} else {
code += `const __script = {}`
}
Expand Down Expand Up @@ -299,12 +303,3 @@ async function compileSFCStyle(
debug(`${publicPath} style compiled in ${Date.now() - start}ms`)
return result
}

function genSourceMapString(map: object | undefined) {
if (!map) {
return ''
}
return `\n//# sourceMappingURL=data:application/json;base64,${Buffer.from(
JSON.stringify(map)
).toString('base64')}`
}
12 changes: 12 additions & 0 deletions src/node/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -109,3 +109,15 @@ export async function readBody(
return !stream || typeof stream === 'string' ? stream : stream.toString()
}
}

export function genSourceMapString(map: object | string | undefined) {
if (!map) {
return ''
}
if (typeof map !== 'string') {
map = JSON.stringify(map)
}
return `\n//# sourceMappingURL=data:application/json;base64,${Buffer.from(
map
).toString('base64')}`
}

0 comments on commit 7cbaf5d

Please sign in to comment.