feat: support typescript via esbuild (closes #42)

This commit is contained in:
Pooya Parsa 2020-11-28 22:11:14 +01:00
parent ca015deda6
commit 7ae8483d21
3 changed files with 172 additions and 0 deletions

View File

@ -30,6 +30,9 @@ export default function (nuxt, moduleContainer) {
// Expose process.env.SIGMA_PRESET
nuxt.options.env.SIGMA_PRESET = sigmaContext.preset
// .ts is supported for serverMiddleware
nuxt.options.extensions.push('ts')
// Replace nuxt server
if (nuxt.server) {
nuxt.server.__closed = true

View File

@ -20,6 +20,7 @@ import { dynamicRequire } from './dynamic-require'
import { externals } from './externals'
import { timing } from './timing'
import { autoMock } from './automock'
import esbuild from './esbuild'
export type RollupConfig = InputOptions & { output: OutputOptions }
@ -110,6 +111,9 @@ export const getRollupConfig = (sigmaContext: SigmaContext) => {
}
}))
// ESBuild (typescript)
rollupConfig.plugins.push(esbuild({}))
// Dynamic Require Support
rollupConfig.plugins.push(dynamicRequire({
dir: resolve(sigmaContext._nuxt.buildDir, 'dist/server'),

View File

@ -0,0 +1,165 @@
// Based on https://github.com/egoist/rollup-plugin-esbuild (MIT)
import { existsSync, statSync } from 'fs'
import { extname, resolve, dirname, join, relative } from 'path'
import { Plugin, PluginContext } from 'rollup'
import { startService, Loader, Service, TransformResult } from 'esbuild'
import { createFilter, FilterPattern } from '@rollup/pluginutils'
const defaultLoaders: { [ext: string]: Loader } = {
'.ts': 'ts'
}
export type Options = {
include?: FilterPattern
exclude?: FilterPattern
sourceMap?: boolean
minify?: boolean
target?: string | string[]
jsxFactory?: string
jsxFragment?: string
define?: {
[k: string]: string
}
/**
* Use this tsconfig file instead
* Disable it by setting to `false`
*/
tsconfig?: string | false
/**
* Map extension to esbuild loader
* Note that each entry (the extension) needs to start with a dot
*/
loaders?: {
[ext: string]: Loader | false
}
}
export default (options: Options = {}): Plugin => {
let target: string | string[]
const loaders = {
...defaultLoaders
}
if (options.loaders) {
for (const key of Object.keys(options.loaders)) {
const value = options.loaders[key]
if (typeof value === 'string') {
loaders[key] = value
} else if (value === false) {
delete loaders[key]
}
}
}
const extensions: string[] = Object.keys(loaders)
const INCLUDE_REGEXP = new RegExp(
`\\.(${extensions.map(ext => ext.slice(1)).join('|')})$`
)
const EXCLUDE_REGEXP = /node_modules/
const filter = createFilter(
options.include || INCLUDE_REGEXP,
options.exclude || EXCLUDE_REGEXP
)
let service: Service | undefined
const stopService = () => {
if (service) {
service.stop()
service = undefined
}
}
return {
name: 'esbuild',
async buildStart () {
if (!service) {
service = await startService()
}
},
async transform (code, id) {
if (!filter(id)) {
return null
}
const ext = extname(id)
const loader = loaders[ext]
if (!loader || !service) {
return null
}
target = options.target || 'node12'
const result = await service.transform(code, {
loader,
target,
define: options.define,
sourcemap: options.sourceMap !== false,
sourcefile: id
})
printWarnings(id, result, this)
return (
result.code && {
code: result.code,
map: result.map || null
}
)
},
buildEnd (error) {
// Stop the service early if there's error
if (error && !this.meta.watchMode) {
stopService()
}
},
async renderChunk (code) {
if (options.minify && service) {
const result = await service.transform(code, {
loader: 'js',
minify: true,
target
})
if (result.code) {
return {
code: result.code,
map: result.map || null
}
}
}
return null
},
generateBundle () {
if (!this.meta.watchMode) {
stopService()
}
}
}
}
function printWarnings (
id: string,
result: TransformResult,
plugin: PluginContext
) {
if (result.warnings) {
for (const warning of result.warnings) {
let message = '[esbuild]'
if (warning.location) {
message += ` (${relative(process.cwd(), id)}:${warning.location.line}:${warning.location.column
})`
}
message += ` ${warning.text}`
plugin.warn(message)
}
}
}