mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 08:33:53 +00:00
feat(nuxi): add nuxi preview
command for local testing (#2162)
Co-authored-by: pooya parsa <pyapar@gmail.com>
This commit is contained in:
parent
279bfdc5b3
commit
b5618e976b
@ -66,6 +66,16 @@ npm run build
|
||||
|
||||
Nuxt will create a [`.output`](/docs/directory-structure/output) directory with all your application, server and dependencies ready to be deployed. Check out the [deployment](/docs/deployment) section to learn where and how you can deploy a Nuxt application using Nitro.
|
||||
|
||||
## Previewing your production build
|
||||
|
||||
Once you've built your Nuxt application, you can preview it locally:
|
||||
|
||||
```bash
|
||||
npx nuxi preview
|
||||
```
|
||||
|
||||
If you're using a supported preset, this will start a local server (for testing purposes only).
|
||||
|
||||
## Upgrade Nuxt3 version
|
||||
|
||||
To upgrade Nuxt3 version:
|
||||
|
@ -4,7 +4,7 @@ import * as rollup from 'rollup'
|
||||
import fse from 'fs-extra'
|
||||
import { printFSTree } from './utils/tree'
|
||||
import { getRollupConfig } from './rollup/config'
|
||||
import { hl, prettyPath, serializeTemplate, writeFile, isDirectory, readDirRecursively } from './utils'
|
||||
import { hl, prettyPath, serializeTemplate, writeFile, isDirectory, readDirRecursively, replaceAll } from './utils'
|
||||
import { NitroContext } from './context'
|
||||
import { scanMiddleware } from './server/middleware'
|
||||
|
||||
@ -107,10 +107,35 @@ async function _build (nitroContext: NitroContext) {
|
||||
consola.start('Writing server bundle...')
|
||||
await build.write(nitroContext.rollupConfig.output)
|
||||
|
||||
const rewriteBuildPaths = (input: unknown, to: string) =>
|
||||
typeof input === 'string' ? replaceAll(input, nitroContext.output.dir, to) : undefined
|
||||
|
||||
// Write build info
|
||||
const nitroConfigPath = resolve(nitroContext.output.dir, 'nitro.json')
|
||||
const buildInfo = {
|
||||
date: new Date(),
|
||||
preset: nitroContext.preset,
|
||||
commands: {
|
||||
preview: rewriteBuildPaths(nitroContext.commands.preview, '.'),
|
||||
deploy: rewriteBuildPaths(nitroContext.commands.deploy, '.')
|
||||
}
|
||||
}
|
||||
await writeFile(nitroConfigPath, JSON.stringify(buildInfo, null, 2))
|
||||
|
||||
consola.success('Server built')
|
||||
await printFSTree(nitroContext.output.serverDir)
|
||||
await nitroContext._internal.hooks.callHook('nitro:compiled', nitroContext)
|
||||
|
||||
// Show deploy and preview hints
|
||||
const rOutDir = relative(process.cwd(), nitroContext.output.dir)
|
||||
if (nitroContext.commands.preview) {
|
||||
// consola.info(`You can preview this build using \`${rewriteBuildPaths(nitroContext.commands.preview, rOutDir)}\``)
|
||||
consola.info('You can preview this build using `nuxi preview`')
|
||||
}
|
||||
if (nitroContext.commands.deploy) {
|
||||
consola.info(`You can deploy this build using \`${rewriteBuildPaths(nitroContext.commands.deploy, rOutDir)}\``)
|
||||
}
|
||||
|
||||
return {
|
||||
entry: resolve(nitroContext.rollupConfig.output.dir, nitroContext.rollupConfig.output.entryFileNames as string)
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import { createHooks, Hookable, NestedHooks } from 'hookable'
|
||||
import type { Preset } from 'unenv'
|
||||
import type { NuxtHooks, NuxtOptions } from '@nuxt/schema'
|
||||
import type { PluginVisualizerOptions } from 'rollup-plugin-visualizer'
|
||||
import { tryImport, resolvePath, detectTarget, extendPreset } from './utils'
|
||||
import { tryImport, resolvePath, detectTarget, extendPreset, evalTemplate } from './utils'
|
||||
import * as PRESETS from './presets'
|
||||
import type { NodeExternalsOptions } from './rollup/plugins/externals'
|
||||
import type { StorageOptions } from './rollup/plugins/storage'
|
||||
@ -40,6 +40,10 @@ export interface NitroContext {
|
||||
experiments?: {
|
||||
wasm?: boolean
|
||||
}
|
||||
commands: {
|
||||
preview: string | ((config: NitroContext) => string)
|
||||
deploy: string | ((config: NitroContext) => string)
|
||||
},
|
||||
moduleSideEffects: string[]
|
||||
renderer: string
|
||||
serveStatic: boolean
|
||||
@ -104,6 +108,10 @@ export function getNitroContext (nuxtOptions: NuxtOptions, input: NitroInput): N
|
||||
moduleSideEffects: ['unenv/runtime/polyfill/'],
|
||||
renderer: undefined,
|
||||
serveStatic: undefined,
|
||||
commands: {
|
||||
preview: undefined,
|
||||
deploy: undefined
|
||||
},
|
||||
middleware: [],
|
||||
scannedMiddleware: [],
|
||||
ignore: [],
|
||||
@ -164,6 +172,13 @@ export function getNitroContext (nuxtOptions: NuxtOptions, input: NitroInput): N
|
||||
nitroContext.output.publicDir = resolvePath(nitroContext, nitroContext.output.publicDir)
|
||||
nitroContext.output.serverDir = resolvePath(nitroContext, nitroContext.output.serverDir)
|
||||
|
||||
if (nitroContext.commands.preview) {
|
||||
nitroContext.commands.preview = evalTemplate(nitroContext, nitroContext.commands.preview)
|
||||
}
|
||||
if (nitroContext.commands.deploy) {
|
||||
nitroContext.commands.deploy = evalTemplate(nitroContext, nitroContext.commands.deploy)
|
||||
}
|
||||
|
||||
nitroContext._internal.hooks.addHooks(nitroContext.hooks)
|
||||
|
||||
// Dev-only storage
|
||||
|
@ -1,8 +1,7 @@
|
||||
import consola from 'consola'
|
||||
import fse from 'fs-extra'
|
||||
import globby from 'globby'
|
||||
import { join, resolve } from 'pathe'
|
||||
import { hl, prettyPath, writeFile } from '../utils'
|
||||
import { writeFile } from '../utils'
|
||||
import { NitroPreset, NitroContext } from '../context'
|
||||
|
||||
export const azure: NitroPreset = {
|
||||
@ -11,6 +10,9 @@ export const azure: NitroPreset = {
|
||||
output: {
|
||||
serverDir: '{{ output.dir }}/server/functions'
|
||||
},
|
||||
commands: {
|
||||
preview: 'npx @azure/static-web-apps-cli start {{ output.publicDir }} --api-location {{ output.serverDir }}/..'
|
||||
},
|
||||
hooks: {
|
||||
async 'nitro:compiled' (ctx: NitroContext) {
|
||||
await writeRoutes(ctx)
|
||||
@ -101,8 +103,4 @@ async function writeRoutes ({ output }: NitroContext) {
|
||||
if (!indexFileExists) {
|
||||
await writeFile(indexPath, '')
|
||||
}
|
||||
|
||||
const apiDir = resolve(output.serverDir, '..')
|
||||
|
||||
consola.success('Ready to run', hl('npx @azure/static-web-apps-cli start ' + prettyPath(output.publicDir) + ' --api-location ' + prettyPath(apiDir)), 'for local testing')
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
import { createWriteStream } from 'fs'
|
||||
import archiver from 'archiver'
|
||||
import consola from 'consola'
|
||||
import { join, resolve } from 'pathe'
|
||||
import { prettyPath, writeFile } from '../utils'
|
||||
import { writeFile } from '../utils'
|
||||
import { NitroPreset, NitroContext } from '../context'
|
||||
|
||||
// eslint-disable-next-line
|
||||
@ -10,6 +9,9 @@ export const azure_functions: NitroPreset = {
|
||||
serveStatic: true,
|
||||
entry: '{{ _internal.runtimeDir }}/entries/azure_functions',
|
||||
externals: true,
|
||||
commands: {
|
||||
deploy: 'az functionapp deployment source config-zip -g <resource-group> -n <app-name> --src {{ output.dir }}/deploy.zip'
|
||||
},
|
||||
hooks: {
|
||||
async 'nitro:compiled' (ctx: NitroContext) {
|
||||
await writeRoutes(ctx)
|
||||
@ -67,9 +69,5 @@ async function writeRoutes ({ output: { dir, serverDir } }: NitroContext) {
|
||||
|
||||
await writeFile(resolve(serverDir, 'function.json'), JSON.stringify(functionDefinition))
|
||||
await writeFile(resolve(dir, 'host.json'), JSON.stringify(host))
|
||||
|
||||
await zipDirectory(dir, join(dir, 'deploy.zip'))
|
||||
const zipPath = prettyPath(resolve(dir, 'deploy.zip'))
|
||||
|
||||
consola.success(`Ready to run \`az functionapp deployment source config-zip -g <resource-group> -n <app-name> --src ${zipPath}\``)
|
||||
}
|
||||
|
@ -1,6 +1,5 @@
|
||||
import { resolve } from 'pathe'
|
||||
import consola from 'consola'
|
||||
import { extendPreset, writeFile, prettyPath, hl } from '../utils'
|
||||
import { extendPreset, writeFile } from '../utils'
|
||||
import { NitroContext, NitroPreset } from '../context'
|
||||
import { worker } from './worker'
|
||||
|
||||
@ -9,15 +8,14 @@ export const cloudflare: NitroPreset = extendPreset(worker, {
|
||||
ignore: [
|
||||
'wrangler.toml'
|
||||
],
|
||||
commands: {
|
||||
preview: 'npx miniflare {{ output.serverDir }}/index.mjs --site {{ output.publicDir }}',
|
||||
deploy: 'cd {{ output.serverDir }} && npx wrangler publish'
|
||||
},
|
||||
hooks: {
|
||||
async 'nitro:compiled' ({ output, _nuxt }: NitroContext) {
|
||||
await writeFile(resolve(output.dir, 'package.json'), JSON.stringify({ private: true, main: './server/index.mjs' }, null, 2))
|
||||
await writeFile(resolve(output.dir, 'package-lock.json'), JSON.stringify({ lockfileVersion: 1 }, null, 2))
|
||||
let inDir = prettyPath(_nuxt.rootDir)
|
||||
if (inDir) {
|
||||
inDir = 'in ' + inDir
|
||||
}
|
||||
consola.success('Ready to run', hl('npx wrangler publish ' + inDir), 'or', hl('npx miniflare ' + prettyPath(output.serverDir) + '/index.mjs --site ' + prettyPath(output.publicDir)), 'for local testing')
|
||||
}
|
||||
}
|
||||
})
|
||||
|
@ -1,7 +1,6 @@
|
||||
import { createRequire } from 'module'
|
||||
import { join, relative, resolve } from 'pathe'
|
||||
import fse from 'fs-extra'
|
||||
import consola from 'consola'
|
||||
import globby from 'globby'
|
||||
import { readPackageJSON } from 'pkg-types'
|
||||
import { writeFile } from '../utils'
|
||||
@ -10,6 +9,9 @@ import { NitroPreset, NitroContext } from '../context'
|
||||
export const firebase: NitroPreset = {
|
||||
entry: '{{ _internal.runtimeDir }}/entries/firebase',
|
||||
externals: true,
|
||||
commands: {
|
||||
deploy: 'npx firebase deploy'
|
||||
},
|
||||
hooks: {
|
||||
async 'nitro:compiled' (ctx: NitroContext) {
|
||||
await writeRoutes(ctx)
|
||||
@ -85,6 +87,4 @@ async function writeRoutes ({ output: { publicDir, serverDir }, _nuxt: { rootDir
|
||||
2
|
||||
)
|
||||
)
|
||||
|
||||
consola.success('Ready to run `firebase deploy`')
|
||||
}
|
||||
|
@ -1,14 +1,11 @@
|
||||
import consola from 'consola'
|
||||
import { extendPreset, hl, prettyPath } from '../utils'
|
||||
import { NitroPreset, NitroContext } from '../context'
|
||||
import { extendPreset } from '../utils'
|
||||
import { NitroPreset } from '../context'
|
||||
import { node } from './node'
|
||||
|
||||
export const server: NitroPreset = extendPreset(node, {
|
||||
entry: '{{ _internal.runtimeDir }}/entries/server',
|
||||
serveStatic: true,
|
||||
hooks: {
|
||||
'nitro:compiled' ({ output }: NitroContext) {
|
||||
consola.success('Ready to run', hl('node ' + prettyPath(output.serverDir) + '/index.mjs'))
|
||||
}
|
||||
commands: {
|
||||
preview: 'node {{ output.serverDir }}/index.mjs'
|
||||
}
|
||||
})
|
||||
|
@ -51,18 +51,22 @@ export async function writeFile (file: string, contents: string, log = false) {
|
||||
}
|
||||
}
|
||||
|
||||
export function resolvePath (nitroContext: NitroInput, path: string | ((nitroContext: NitroInput) => string), resolveBase: string = ''): string {
|
||||
if (typeof path === 'function') {
|
||||
path = path(nitroContext)
|
||||
export function evalTemplate (ctx, input: string | ((ctx) => string)): string {
|
||||
if (typeof input === 'function') {
|
||||
input = input(ctx)
|
||||
}
|
||||
|
||||
if (typeof path !== 'string') {
|
||||
throw new TypeError('Invalid path: ' + path)
|
||||
if (typeof input !== 'string') {
|
||||
throw new TypeError('Invalid template: ' + input)
|
||||
}
|
||||
return compileTemplate(input)(ctx)
|
||||
}
|
||||
|
||||
path = compileTemplate(path)(nitroContext)
|
||||
export function resolvePath (nitroContext: NitroInput, input: string | ((nitroContext: NitroInput) => string), resolveBase: string = ''): string {
|
||||
return resolve(resolveBase, evalTemplate(nitroContext, input))
|
||||
}
|
||||
|
||||
return resolve(resolveBase, path)
|
||||
export function replaceAll (input: string, from: string, to: string) {
|
||||
return input.replace(new RegExp(from, 'g'), to)
|
||||
}
|
||||
|
||||
export function detectTarget () {
|
||||
|
@ -5,6 +5,8 @@ const _rDefault = r => r.default || r
|
||||
export const commands = {
|
||||
dev: () => import('./dev').then(_rDefault),
|
||||
build: () => import('./build').then(_rDefault),
|
||||
preview: () => import('./preview').then(_rDefault),
|
||||
start: () => import('./preview').then(_rDefault),
|
||||
analyze: () => import('./analyze').then(_rDefault),
|
||||
generate: () => import('./generate').then(_rDefault),
|
||||
prepare: () => import('./prepare').then(_rDefault),
|
||||
|
42
packages/nuxi/src/commands/preview.ts
Normal file
42
packages/nuxi/src/commands/preview.ts
Normal file
@ -0,0 +1,42 @@
|
||||
import { existsSync, promises as fsp } from 'fs'
|
||||
import { dirname, relative } from 'path'
|
||||
import { execa } from 'execa'
|
||||
import { resolve } from 'pathe'
|
||||
import consola from 'consola'
|
||||
|
||||
import { defineNuxtCommand } from './index'
|
||||
|
||||
export default defineNuxtCommand({
|
||||
meta: {
|
||||
name: 'preview',
|
||||
usage: 'npx nuxi preview|start [rootDir]',
|
||||
description: 'Launches nitro server for local testing after `nuxi build`.'
|
||||
},
|
||||
async invoke (args) {
|
||||
process.env.NODE_ENV = process.env.NODE_ENV || 'production'
|
||||
const rootDir = resolve(args._[0] || '.')
|
||||
|
||||
const nitroJSONPaths = ['.output/nitro.json', 'nitro.json'].map(p => resolve(rootDir, p))
|
||||
const nitroJSONPath = nitroJSONPaths.find(p => existsSync(p))
|
||||
if (!nitroJSONPath) {
|
||||
consola.error('Cannot find `nitro.json`. Did you run `nuxi build` first? Search path:\n', nitroJSONPaths)
|
||||
process.exit(1)
|
||||
}
|
||||
const outputPath = dirname(nitroJSONPath)
|
||||
const nitroJSON = JSON.parse(await fsp.readFile(nitroJSONPath, 'utf-8'))
|
||||
|
||||
consola.info('Node.js version:', process.versions.node)
|
||||
consola.info('Preset:', nitroJSON.preset)
|
||||
consola.info('Working dir:', relative(process.cwd(), outputPath))
|
||||
|
||||
if (!nitroJSON.commands.preview) {
|
||||
consola.error('Preview is not supported for this build.')
|
||||
process.exit(1)
|
||||
}
|
||||
|
||||
consola.info('Starting preview command:', nitroJSON.commands.preview)
|
||||
const [command, ...commandArgs] = nitroJSON.commands.preview.split(' ')
|
||||
consola.log('')
|
||||
await execa(command, commandArgs, { stdio: 'inherit', cwd: outputPath })
|
||||
}
|
||||
})
|
Loading…
Reference in New Issue
Block a user