mirror of
https://github.com/nuxt/nuxt.git
synced 2025-01-30 23:32:38 +00:00
feat: initial support for vite bundler (#127)
This commit is contained in:
parent
9c4a14074c
commit
9be282623c
@ -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'
|
@ -1,5 +1,4 @@
|
||||
import { createApp } from 'vue'
|
||||
|
||||
import { createNuxt, applyPlugins } from 'nuxt/app/nuxt'
|
||||
import plugins from './plugins'
|
||||
import serverPlugins from './plugins.server'
|
@ -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>
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
129
packages/nuxt3/src/builder/vite/vite.ts
Normal file
129
packages/nuxt3/src/builder/vite/vite.ts
Normal 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)
|
||||
})
|
||||
}
|
||||
}
|
@ -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()
|
||||
}
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -1 +0,0 @@
|
||||
export { WebpackBundler as BundleBuilder } from './builder'
|
Loading…
Reference in New Issue
Block a user