mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-27 08:02:01 +00:00
feat(modern): auto detect modern mode (#4422)
This commit is contained in:
parent
8cc954d48e
commit
fe492d8363
@ -12,7 +12,7 @@ export default () => ({
|
|||||||
|
|
||||||
// Mode
|
// Mode
|
||||||
mode: 'universal',
|
mode: 'universal',
|
||||||
modern: false,
|
modern: undefined,
|
||||||
|
|
||||||
// Globals
|
// Globals
|
||||||
globalName: `nuxt`,
|
globalName: `nuxt`,
|
||||||
|
@ -253,10 +253,6 @@ export function getNuxtConfig(_options) {
|
|||||||
}
|
}
|
||||||
defaultsDeep(options, modePreset || options.modes.universal)
|
defaultsDeep(options, modePreset || options.modes.universal)
|
||||||
|
|
||||||
if (options.modern === true) {
|
|
||||||
options.modern = 'server'
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no server-side rendering, add appear true transition
|
// If no server-side rendering, add appear true transition
|
||||||
/* istanbul ignore if */
|
/* istanbul ignore if */
|
||||||
if (options.render.ssr === false && options.transition) {
|
if (options.render.ssr === false && options.transition) {
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import chalk from 'chalk'
|
||||||
|
import consola from 'consola'
|
||||||
import { ModernBrowsers } from '@nuxt/common'
|
import { ModernBrowsers } from '@nuxt/common'
|
||||||
import { matchesUA } from 'browserslist-useragent'
|
import { matchesUA } from 'browserslist-useragent'
|
||||||
|
|
||||||
@ -11,12 +13,33 @@ const isModernBrowser = (ua) => {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function (req, res, next) {
|
let detected = false
|
||||||
|
|
||||||
|
const detectModernBuild = ({ options, resources }) => {
|
||||||
|
if (detected === false && ![false, 'client', 'server'].includes(options.modern)) {
|
||||||
|
detected = true
|
||||||
|
if (resources.modernManifest) {
|
||||||
|
options.modern = options.render.ssr ? 'server' : 'client'
|
||||||
|
consola.info(`Modern bundles are detected. Modern mode (${chalk.green.bold(options.modern)}) is enabled now.`)
|
||||||
|
} else {
|
||||||
|
options.modern = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const detectModernBrowser = (req, options) => {
|
||||||
|
if (options.modern === 'server') {
|
||||||
const { socket = {}, headers } = req
|
const { socket = {}, headers } = req
|
||||||
if (socket.modernMode === undefined) {
|
if (socket.modernMode === undefined) {
|
||||||
const ua = headers && headers['user-agent']
|
const ua = headers && headers['user-agent']
|
||||||
socket.modernMode = isModernBrowser(ua)
|
socket.modernMode = isModernBrowser(ua)
|
||||||
}
|
}
|
||||||
req.modernMode = socket.modernMode
|
req.modernMode = socket.modernMode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ({ context }) => (req, res, next) => {
|
||||||
|
detectModernBuild(context)
|
||||||
|
detectModernBrowser(req, context.options)
|
||||||
next()
|
next()
|
||||||
}
|
}
|
||||||
|
@ -10,7 +10,7 @@ import renderAndGetWindow from './jsdom'
|
|||||||
import nuxtMiddleware from './middleware/nuxt'
|
import nuxtMiddleware from './middleware/nuxt'
|
||||||
import errorMiddleware from './middleware/error'
|
import errorMiddleware from './middleware/error'
|
||||||
import Listener from './listener'
|
import Listener from './listener'
|
||||||
import modernMiddleware from './middleware/modern'
|
import createModernMiddleware from './middleware/modern'
|
||||||
|
|
||||||
export default class Server {
|
export default class Server {
|
||||||
constructor(nuxt) {
|
constructor(nuxt) {
|
||||||
@ -79,12 +79,13 @@ export default class Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.options.modern === 'server') {
|
const modernMiddleware = createModernMiddleware({
|
||||||
this.useMiddleware(modernMiddleware)
|
context: this.renderer.context
|
||||||
}
|
})
|
||||||
|
|
||||||
// Add webpack middleware support only for development
|
// Add webpack middleware support only for development
|
||||||
if (this.options.dev) {
|
if (this.options.dev) {
|
||||||
|
this.useMiddleware(modernMiddleware)
|
||||||
this.useMiddleware(async (req, res, next) => {
|
this.useMiddleware(async (req, res, next) => {
|
||||||
const name = req.modernMode ? 'modern' : 'client'
|
const name = req.modernMode ? 'modern' : 'client'
|
||||||
if (this.devMiddleware[name]) {
|
if (this.devMiddleware[name]) {
|
||||||
@ -124,6 +125,7 @@ export default class Server {
|
|||||||
this.options.render.dist
|
this.options.render.dist
|
||||||
)
|
)
|
||||||
})
|
})
|
||||||
|
this.useMiddleware(modernMiddleware)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add user provided middleware
|
// Add user provided middleware
|
||||||
|
@ -223,7 +223,8 @@ export default class VueRenderer {
|
|||||||
rendererOptions
|
rendererOptions
|
||||||
)
|
)
|
||||||
|
|
||||||
if (this.context.options.modern === 'server') {
|
if (this.context.resources.modernManifest &&
|
||||||
|
!['client', false].includes(this.context.options.modern)) {
|
||||||
this.renderer.modern = createBundleRenderer(
|
this.renderer.modern = createBundleRenderer(
|
||||||
this.context.resources.serverBundle,
|
this.context.resources.serverBundle,
|
||||||
{
|
{
|
||||||
|
@ -3,7 +3,7 @@ import { loadFixture, getPort, Nuxt, rp, wChunk } from '../utils'
|
|||||||
let nuxt, port
|
let nuxt, port
|
||||||
const url = route => 'http://localhost:' + port + route
|
const url = route => 'http://localhost:' + port + route
|
||||||
|
|
||||||
describe('modern client mode', () => {
|
describe('modern client mode (SSR)', () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const options = await loadFixture('modern', { modern: 'client' })
|
const options = await loadFixture('modern', { modern: 'client' })
|
||||||
nuxt = new Nuxt(options)
|
nuxt = new Nuxt(options)
|
||||||
|
@ -1,17 +1,25 @@
|
|||||||
|
import chalk from 'chalk'
|
||||||
|
import consola from 'consola'
|
||||||
import { loadFixture, getPort, Nuxt, rp, wChunk } from '../utils'
|
import { loadFixture, getPort, Nuxt, rp, wChunk } from '../utils'
|
||||||
|
|
||||||
let nuxt, port
|
let nuxt, port
|
||||||
const url = route => 'http://localhost:' + port + route
|
const url = route => 'http://localhost:' + port + route
|
||||||
const modernUA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'
|
const modernUA = 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36'
|
||||||
|
const modernInfo = mode => `Modern bundles are detected. Modern mode (${chalk.green.bold(mode)}) is enabled now.`
|
||||||
|
|
||||||
describe('modern server mode', () => {
|
describe('modern server mode', () => {
|
||||||
beforeAll(async () => {
|
beforeAll(async () => {
|
||||||
const options = await loadFixture('modern', { modern: 'server' })
|
const options = await loadFixture('modern')
|
||||||
nuxt = new Nuxt(options)
|
nuxt = new Nuxt(options)
|
||||||
port = await getPort()
|
port = await getPort()
|
||||||
await nuxt.server.listen(port, 'localhost')
|
await nuxt.server.listen(port, 'localhost')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('should detect server modern mode', async () => {
|
||||||
|
await nuxt.server.renderAndGetWindow(url('/'))
|
||||||
|
expect(consola.info).toHaveBeenCalledWith(modernInfo('server'))
|
||||||
|
})
|
||||||
|
|
||||||
test('should use legacy resources by default', async () => {
|
test('should use legacy resources by default', async () => {
|
||||||
const response = await rp(url('/'))
|
const response = await rp(url('/'))
|
||||||
expect(response).toContain('/_nuxt/app.js')
|
expect(response).toContain('/_nuxt/app.js')
|
||||||
|
53
test/unit/modern.spa.test.js
Normal file
53
test/unit/modern.spa.test.js
Normal file
@ -0,0 +1,53 @@
|
|||||||
|
import chalk from 'chalk'
|
||||||
|
import consola from 'consola'
|
||||||
|
import { loadFixture, getPort, Nuxt, rp } from '../utils'
|
||||||
|
|
||||||
|
let nuxt, port, options
|
||||||
|
const url = route => 'http://localhost:' + port + route
|
||||||
|
const modernInfo = mode => `Modern bundles are detected. Modern mode (${chalk.green.bold(mode)}) is enabled now.`
|
||||||
|
|
||||||
|
describe('modern client mode (SPA)', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
options = await loadFixture('modern', { render: { ssr: false } })
|
||||||
|
nuxt = new Nuxt(options)
|
||||||
|
port = await getPort()
|
||||||
|
await nuxt.server.listen(port, 'localhost')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should detect client modern mode', async () => {
|
||||||
|
await nuxt.server.renderAndGetWindow(url('/'))
|
||||||
|
expect(consola.info).toHaveBeenCalledWith(modernInfo('client'))
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should contain nomodule legacy resources', async () => {
|
||||||
|
const response = await rp(url('/'))
|
||||||
|
expect(response).toContain('src="/_nuxt/app.js" nomodule')
|
||||||
|
expect(response).toContain('src="/_nuxt/commons.app.js" nomodule')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should contain module modern resources', async () => {
|
||||||
|
const response = await rp(url('/'))
|
||||||
|
expect(response).toContain('<script type="module" src="/_nuxt/modern-app.js"')
|
||||||
|
expect(response).toContain('<script type="module" src="/_nuxt/modern-commons.app.js"')
|
||||||
|
})
|
||||||
|
|
||||||
|
test.skip('should contain module preload resources', async () => {
|
||||||
|
const response = await rp(url('/'))
|
||||||
|
expect(response).toContain('<link rel="modulepreload" href="/_nuxt/modern-app.js" as="script">')
|
||||||
|
expect(response).toContain('<link rel="modulepreload" href="/_nuxt/modern-commons.app.js" as="script">')
|
||||||
|
})
|
||||||
|
|
||||||
|
test('should contain module http2 pushed resources', async () => {
|
||||||
|
const { headers: { link } } = await rp(url('/'), { resolveWithFullResponse: true })
|
||||||
|
expect(link).toEqual([
|
||||||
|
'</_nuxt/modern-runtime.js>; rel=preload; as=script',
|
||||||
|
'</_nuxt/modern-commons.app.js>; rel=preload; as=script',
|
||||||
|
'</_nuxt/modern-app.js>; rel=preload; as=script'
|
||||||
|
].join(', '))
|
||||||
|
})
|
||||||
|
|
||||||
|
// Close server and ask nuxt to stop listening to file changes
|
||||||
|
afterAll(async () => {
|
||||||
|
await nuxt.close()
|
||||||
|
})
|
||||||
|
})
|
Loading…
Reference in New Issue
Block a user