feat: initial support for vite bundler (#127)

This commit is contained in:
pooya parsa 2021-01-22 23:02:33 +01:00 committed by GitHub
parent 9c4a14074c
commit 9be282623c
38 changed files with 164 additions and 27 deletions

View File

@ -1,3 +1,4 @@
<%= nuxtOptions.vite ? "import('vite/dynamic-import-polyfill')" : '' %>
import { createSSRApp, nextTick } from 'vue'
import { createNuxt, applyPlugins } from 'nuxt/app/nuxt'
import plugins from './plugins'

View File

@ -1,5 +1,4 @@
import { createApp } from 'vue'
import { createNuxt, applyPlugins } from 'nuxt/app/nuxt'
import plugins from './plugins'
import serverPlugins from './plugins.server'

View File

@ -5,5 +5,7 @@
</head>
<body {{ BODY_ATTRS }}>
<div id="__nuxt">{{ APP }}</div>
<% if (nuxtOptions.vite && nuxtOptions.dev) { %><script type="module" src="/@vite/client"></script>
<script type="module" src="/entry.client.js"></script><% } %>
</body>
</html>

View File

@ -1,6 +1,6 @@
import { Ref, toRef, onMounted, watch, getCurrentInstance, onUnmounted } from 'vue'
import { Nuxt, useNuxt } from 'nuxt/app'
import { httpFetch } from '../utils/fetch'
import { $fetch } from 'ohmyfetch'
import { useData } from './data'
export type HTTPRequest = string | { method: string, url: string }
@ -44,7 +44,7 @@ export function useFetch (defaults?: FetchOptions) {
options = {
server: true,
defer: false,
fetcher: httpFetch,
fetcher: globalThis.$fetch || $fetch,
...defaults,
...options
}

View File

@ -1,15 +0,0 @@
// TODO: Move to a nuxt-contrib utility
import destr from 'destr'
// TODO: polyfill by env (nuxt) not by util
const _fetch = process.server ? require('node-fetch') : global.fetch
export async function httpFetch (path: string) {
const res = await _fetch(path)
if (!res.ok) {
throw new Error(res)
}
const data = await res.text()
return destr(data)
}

View File

@ -1,7 +1,6 @@
import { join, relative } from 'path'
import fsExtra from 'fs-extra'
import { debounce } from 'lodash'
import { BundleBuilder } from 'src/webpack'
import { Nuxt } from '../core'
import { DeterminedGlobals, determineGlobals } from '../utils'
import {
@ -73,6 +72,11 @@ function watch (builder: Builder) {
appWatcher.watch(/^(A|a)pp\.[a-z]{2,3}/, refreshTemplates, ['add', 'unlink'])
// Watch for page changes
appWatcher.watch(new RegExp(`^${nuxt.options.dir.pages}/`), refreshTemplates, ['add', 'unlink'])
// Shared Watcher
const watchHookDebounced = debounce((event, file) => builder.nuxt.callHook('builder:watch', event, file), 100)
appWatcher.watchAll(watchHookDebounced)
nuxtAppWatcher.watchAll(watchHookDebounced)
}
export async function generate (builder: Builder) {
@ -90,5 +94,11 @@ export async function generate (builder: Builder) {
}
async function bundle ({ nuxt }: Builder) {
await new BundleBuilder(nuxt).build()
// @ts-ignore
const useVite = !!nuxt.options.vite
const bundle = await (useVite
? import('./vite/vite' /* webpackChunkName: "vite" */)
: import('./webpack/webpack' /* webpackChunkName: "webpack" */))
.then(p => p.bundle)
return bundle(nuxt)
}

View File

@ -12,7 +12,8 @@ export interface NuxtTemplate {
export function templateData (builder) {
return {
globals: builder.globals,
app: builder.app
app: builder.app,
nuxtOptions: builder.nuxt.options
}
}

View File

@ -0,0 +1,129 @@
import { resolve } from 'path'
import { Nuxt } from 'src/core'
import { mkdirp, writeFile } from 'fs-extra'
import createRequire from 'create-require'
import vue from '@vitejs/plugin-vue'
import consola from 'consola'
import * as vite from 'vite'
interface ViteBuildContext {
nuxt: Nuxt
config: vite.InlineConfig
}
export async function bundle (nuxt: Nuxt) {
const ctx: ViteBuildContext = {
nuxt,
config: {
root: nuxt.options.buildDir,
mode: nuxt.options.dev ? 'development' : 'production',
alias: {
'nuxt/app': nuxt.options.appDir,
'~build': nuxt.options.buildDir,
'~': nuxt.options.srcDir,
'@': nuxt.options.srcDir
},
clearScreen: false,
plugins: [
vue({})
],
build: {
emptyOutDir: false
}
}
}
await mkdirp(nuxt.options.buildDir)
const { dependencies = {}, devDependencies = {} } = createRequire(nuxt.options.rootDir)('package.json')
await writeFile(resolve(nuxt.options.buildDir, 'package.json'), JSON.stringify({
private: true,
description: 'auto generated',
devDependencies: { ...dependencies, ...devDependencies }
}, null, 2))
const callBuild = async (fn, name) => {
try {
const start = Date.now()
await fn(ctx)
const time = (Date.now() - start) / 1000
consola.success(`${name} compiled successfully in ${time}s`)
} catch (err) {
consola.error(`${name} compiled with errors:`, err)
}
}
if (nuxt.options.dev) {
await Promise.all([
callBuild(buildClient, 'Client'),
callBuild(buildServer, 'Server')
])
} else {
await callBuild(buildClient, 'Client')
await callBuild(buildServer, 'Server')
}
}
async function buildClient (ctx: ViteBuildContext) {
const clientConfig: vite.InlineConfig = vite.mergeConfig(ctx.config, {
define: {
'process.server': false,
'process.client': true
},
build: {
outDir: 'dist/client',
assetsDir: '.',
ssrManifest: true,
manifest: true,
rollupOptions: {
input: resolve(ctx.nuxt.options.buildDir, './entry.client.js')
}
},
server: {
middlewareMode: true
}
} as vite.InlineConfig)
if (ctx.nuxt.options.dev) {
const viteServer = await vite.createServer(clientConfig)
await ctx.nuxt.callHook('server:devMiddleware', (req, res, next) => {
// Workaround: vite devmiddleware modifies req.url
const originalURL = req.url
viteServer.middlewares.handle(req, res, (err) => {
req.url = originalURL
next(err)
})
})
} else {
await vite.build(clientConfig)
}
}
async function buildServer (ctx: ViteBuildContext) {
const serverConfig: vite.InlineConfig = vite.mergeConfig(ctx.config, {
define: {
'process.server': true,
'process.client': false,
window: undefined
},
build: {
outDir: 'dist/server',
ssr: true,
rollupOptions: {
input: resolve(ctx.nuxt.options.buildDir, './entry.server.js')
}
}
} as vite.InlineConfig)
const serverDist = resolve(ctx.nuxt.options.buildDir, 'dist/server')
await mkdirp(serverDist)
await writeFile(resolve(serverDist, 'client.manifest.json'), 'false')
await writeFile(resolve(serverDist, 'server.js'), 'const entry = require("./entry.server.js"); module.exports = entry.default || entry;')
await vite.build(serverConfig)
if (ctx.nuxt.options.dev) {
ctx.nuxt.hook('builder:watch', () => {
vite.build(serverConfig).catch(consola.error)
})
}
}

View File

@ -13,7 +13,7 @@ import { createWebpackConfigContext, applyPresets, getWebpackConfig } from './ut
const glob = pify(Glob)
export class WebpackBundler {
class WebpackBundler {
nuxt: Nuxt
plugins: Array<string>
@ -251,3 +251,8 @@ export class WebpackBundler {
this.nuxt.options.target = TARGETS.static
}
}
export function bundle (nuxt: Nuxt) {
const bundler = new WebpackBundler(nuxt)
return bundler.build()
}

View File

@ -85,7 +85,8 @@ interface CommonConfiguration {
_nuxtConfigFile?: string
alias: Record<string, string>
appDir: string,
buildDir: string
buildDir: string,
vite: boolean,
buildModules: NuxtModule[]
createRequire?: (module: NodeJS.Module) => NodeJS.Require
debug?: boolean

View File

@ -71,11 +71,11 @@ export async function loadNuxtConfig ({
// Clear cache
clearRequireCache(configFile)
const _require = createRequire(module)
const _config: Configuration | ((ctx: Record<string, any>) => Promise<Configuration>) = interopDefault(_require(configFile) || {})
let _config: Configuration | ((ctx: Record<string, any>) => Promise<Configuration>) = interopDefault(_require(configFile) || {})
if (typeof _config === 'function') {
try {
options = interopDefault(await _config(configContext))
_config = interopDefault(await _config(configContext))
} catch (error) {
consola.error(error)
consola.fatal('Error while fetching async configuration')
@ -83,7 +83,7 @@ export async function loadNuxtConfig ({
}
// Don't mutate options export
options = { ...options }
options = { ..._config }
// Keep _nuxtConfigFile for watching
options._nuxtConfigFile = configFile

View File

@ -442,6 +442,11 @@ function normalizeConfig (_options: CliConfiguration) {
options._majorVersion = 3
if (options.vite && !options.dev) {
options.vite = false
consola.warn('Vite does not support production builds yet! Using webpack...')
}
return options
}

View File

@ -1 +0,0 @@
export { WebpackBundler as BundleBuilder } from './builder'