Skip to content

Commit

Permalink
feat: resolve plugins + support vueCompilerOptions
Browse files Browse the repository at this point in the history
  • Loading branch information
yyx990803 committed May 9, 2020
1 parent ab940fd commit 7cdaa0b
Show file tree
Hide file tree
Showing 5 changed files with 114 additions and 60 deletions.
5 changes: 3 additions & 2 deletions src/node/build/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ export async function build(options: BuildConfig = {}): Promise<BuildResult> {
assetsDir = 'assets',
assetsInlineLimit = 4096,
resolvers = [],
vueCompilerOptions,
rollupInputOptions = {},
rollupOutputOptions = {},
rollupPluginVueOptions = {},
Expand Down Expand Up @@ -102,13 +103,13 @@ export async function build(options: BuildConfig = {}): Promise<BuildResult> {
await createEsbuildPlugin(minify === 'esbuild', jsx),
// vue
require('rollup-plugin-vue')({
...rollupPluginVueOptions,
transformAssetUrls: {
includeAbsolute: true
},
preprocessStyles: true,
preprocessCustomRequire: (id: string) => require(resolve(root, id)),
// TODO proxy cssModules config
...rollupPluginVueOptions
compilerOptions: vueCompilerOptions
}),
require('@rollup/plugin-json')(),
require('@rollup/plugin-node-resolve')({
Expand Down
125 changes: 87 additions & 38 deletions src/node/config.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
import path from 'path'
import fs from 'fs-extra'
import chalk from 'chalk'
import { createEsbuildPlugin } from './build/buildPluginEsbuild'
import { ServerPlugin } from './server'
import { Resolver } from './resolver'
import {
import { Options as RollupPluginVueOptions } from 'rollup-plugin-vue'
import { CompilerOptions } from '@vue/compiler-sfc'
import Rollup, {
InputOptions as RollupInputOptions,
OutputOptions as RollupOutputOptions
} from 'rollup'
import { Options as RollupPluginVueOptions } from 'rollup-plugin-vue'

/**
* Options shared between server and build.
Expand All @@ -29,6 +34,10 @@ export interface SharedConfig {
* and optionally map module ids to public path requests.
*/
resolvers?: Resolver[]
/**
* Options to pass to @vue/compiler-dom
*/
vueCompilerOptions?: CompilerOptions
/**
* Configure what to use for jsx factory and fragment.
* @default
Expand Down Expand Up @@ -127,6 +136,7 @@ export interface BuildConfig extends SharedConfig {
}

export interface UserConfig extends BuildConfig {
configureServer?: ServerPlugin
plugins?: Plugin[]
}

Expand All @@ -144,19 +154,16 @@ export interface Transform {
}

export interface Plugin
extends Pick<SharedConfig, 'alias' | 'transforms' | 'resolvers'>,
Pick<
BuildConfig,
'rollupInputOptions' | 'rollupOutputOptions' | 'rollupPluginVueOptions'
> {
configureServer?: ServerPlugin
}

import path from 'path'
import fs from 'fs-extra'
import chalk from 'chalk'
import type Rollup from 'rollup'
import { createEsbuildPlugin } from './build/buildPluginEsbuild'
extends Pick<
UserConfig,
| 'alias'
| 'transforms'
| 'resolvers'
| 'configureServer'
| 'vueCompilerOptions'
| 'rollupInputOptions'
| 'rollupOutputOptions'
> {}

export async function resolveConfig(
configPath: string | undefined
Expand All @@ -168,11 +175,12 @@ export async function resolveConfig(
)
try {
if (await fs.pathExists(resolvedPath)) {
let config: UserConfig | undefined
const isTs = path.extname(resolvedPath) === '.ts'
// 1. try loading the config file directly
if (!isTs) {
try {
return require(resolvedPath)
config = require(resolvedPath)
} catch (e) {
if (
!/Cannot use import statement|Unexpected token 'export'/.test(
Expand All @@ -184,32 +192,42 @@ export async function resolveConfig(
}
}

// 2. if we reach here, the file is ts or using es import syntax.
// transpile es import syntax to require syntax using rollup.
const rollup = require('rollup') as typeof Rollup
const esbuilPlugin = await createEsbuildPlugin(false, {})
const bundle = await rollup.rollup({
external: (id: string) =>
(id[0] !== '.' && !path.isAbsolute(id)) ||
id.slice(-5, id.length) === '.json',
input: resolvedPath,
treeshake: false,
plugins: [esbuilPlugin]
})

const {
output: [{ code }]
} = await bundle.generate({
exports: 'named',
format: 'cjs'
})

const config = await loadConfigFromBundledFile(resolvedPath, code)
if (!config) {
// 2. if we reach here, the file is ts or using es import syntax.
// transpile es import syntax to require syntax using rollup.
const rollup = require('rollup') as typeof Rollup
const esbuilPlugin = await createEsbuildPlugin(false, {})
const bundle = await rollup.rollup({
external: (id: string) =>
(id[0] !== '.' && !path.isAbsolute(id)) ||
id.slice(-5, id.length) === '.json',
input: resolvedPath,
treeshake: false,
plugins: [esbuilPlugin]
})

const {
output: [{ code }]
} = await bundle.generate({
exports: 'named',
format: 'cjs'
})

config = await loadConfigFromBundledFile(resolvedPath, code)
}

// normalize config root to absolute
if (config.root && !path.isAbsolute(config.root)) {
config.root = path.resolve(path.dirname(resolvedPath), config.root)
}

// resolve plugins
if (config.plugins) {
for (const plugin of config.plugins) {
config = resolvePlugin(config, plugin)
}
}

require('debug')('vite:config')(
`config resolved in ${Date.now() - start}ms`
)
Expand All @@ -232,7 +250,7 @@ interface NodeModuleWithCompile extends NodeModule {
async function loadConfigFromBundledFile(
fileName: string,
bundledCode: string
) {
): Promise<UserConfig> {
const extension = path.extname(fileName)
const defaultLoader = require.extensions[extension]!
require.extensions[extension] = (module: NodeModule, filename: string) => {
Expand All @@ -248,3 +266,34 @@ async function loadConfigFromBundledFile(
require.extensions[extension] = defaultLoader
return config
}

function resolvePlugin(config: UserConfig, plugin: Plugin): UserConfig {
return {
alias: {
...plugin.alias,
...config.alias
},
transforms: [...(config.transforms || []), ...(plugin.transforms || [])],
resolvers: [...(config.resolvers || []), ...(plugin.resolvers || [])],
configureServer: (ctx) => {
if (config.configureServer) {
config.configureServer(ctx)
}
if (plugin.configureServer) {
plugin.configureServer(ctx)
}
},
vueCompilerOptions: {
...config.vueCompilerOptions,
...plugin.vueCompilerOptions
},
rollupInputOptions: {
...config.rollupInputOptions,
...plugin.rollupInputOptions
},
rollupOutputOptions: {
...config.rollupOutputOptions,
...plugin.rollupOutputOptions
}
}
}
17 changes: 3 additions & 14 deletions src/node/server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,7 @@ export interface ServerPluginContext {
server: Server
watcher: HMRWatcher
resolver: InternalResolver
jsxConfig: {
jsxFactory: string | undefined
jsxFragment: string | undefined
}
config: ServerConfig
}

const internalPlugins: ServerPlugin[] = [
Expand All @@ -42,12 +39,7 @@ const internalPlugins: ServerPlugin[] = [
]

export function createServer(config: ServerConfig = {}): Server {
const {
root = process.cwd(),
plugins = [],
resolvers = [],
jsx = {}
} = config
const { root = process.cwd(), plugins = [], resolvers = [] } = config
const app = new Koa()
const server = http.createServer(app.callback())
const watcher = chokidar.watch(root, {
Expand All @@ -60,10 +52,7 @@ export function createServer(config: ServerConfig = {}): Server {
server,
watcher,
resolver,
jsxConfig: {
jsxFactory: jsx.factory,
jsxFragment: jsx.fragment
}
config
}

;[...plugins, ...internalPlugins].forEach((m) => m(context))
Expand Down
9 changes: 7 additions & 2 deletions src/node/server/serverPluginEsbuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,18 @@ import { ServerPlugin } from '.'
import { tjsxRE, transform } from '../esbuildService'
import { readBody, genSourceMapString } from '../utils'

export const esbuildPlugin: ServerPlugin = ({ app, jsxConfig }) => {
export const esbuildPlugin: ServerPlugin = ({ app, config }) => {
const options = {
jsxFactory: config.jsx && config.jsx.factory,
jsxFragment: config.jsx && config.jsx.fragment
}

app.use(async (ctx, next) => {
await next()
if (ctx.body && tjsxRE.test(ctx.path)) {
ctx.type = 'js'
const src = await readBody(ctx.body)
const { code, map } = await transform(src!, ctx.path, jsxConfig)
const { code, map } = await transform(src!, ctx.path, options)
let res = code
if (map) {
res += genSourceMapString(map)
Expand Down
18 changes: 14 additions & 4 deletions src/node/server/serverPluginVue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ import {
SFCTemplateBlock,
SFCStyleBlock,
SFCStyleCompileResults,
generateCodeFrame
generateCodeFrame,
CompilerOptions
} from '@vue/compiler-sfc'
import { resolveCompiler } from '../utils/resolveVue'
import hash_sum from 'hash-sum'
Expand Down Expand Up @@ -52,7 +53,13 @@ const etagCacheCheck = (ctx: Context) => {
ctx.status = ctx.etag === ctx.get('If-None-Match') ? 304 : 200
}

export const vuePlugin: ServerPlugin = ({ root, app, resolver, watcher }) => {
export const vuePlugin: ServerPlugin = ({
root,
app,
resolver,
watcher,
config
}) => {
app.use(async (ctx, next) => {
if (!ctx.path.endsWith('.vue') && !ctx.vue) {
return next()
Expand Down Expand Up @@ -90,7 +97,8 @@ export const vuePlugin: ServerPlugin = ({ root, app, resolver, watcher }) => {
templateBlock,
filename,
publicPath,
descriptor.styles.some((s) => s.scoped)
descriptor.styles.some((s) => s.scoped),
config.vueCompilerOptions
)
return etagCacheCheck(ctx)
}
Expand Down Expand Up @@ -287,7 +295,8 @@ function compileSFCTemplate(
template: SFCTemplateBlock,
filename: string,
publicPath: string,
scoped: boolean
scoped: boolean,
userOptions: CompilerOptions | undefined
): string {
let cached = vueCache.get(filename)
if (cached && cached.template) {
Expand All @@ -304,6 +313,7 @@ function compileSFCTemplate(
base: path.posix.dirname(publicPath)
},
compilerOptions: {
...userOptions,
scopeId: scoped ? `data-v-${hash_sum(publicPath)}` : null,
runtimeModuleName: '/@modules/vue'
},
Expand Down

0 comments on commit 7cdaa0b

Please sign in to comment.