Nuxt/packages/generator/test/generator.init.test.js
Sébastien Chopin 917adc0618
feat: options.target and full-static export (#6159)
* feat: add options.target

* fix(lint): lint

* fix(test): update snapshots

* fix(builder): default value for target

* fix(test): fix test

* fix(test): test fixing

* fix: use this.options.target

* fix: final test

* Update packages/vue-renderer/src/renderer.js

Co-Authored-By: Alexander Lichter <manniL@gmx.net>

* feat: Add target option and update banner

* fix(lint): fix

* feat: Add warning when using serverMiddleware in static target

* chore(utils): add TARGETS and MODES as constants

* hotfix: lint

* chore(module): add filename as alias of fileName

* feat: introducing nuxt export and router/routes.json

* hotfix: Fix the linting lord

* chore(core): add comment for filename vs fileName

* fix: use targets constant

* chore: remove warning

* fix: unit testing

* wip: refactor and use TARGETS

* fix: lint

* feat: add target as alias for first arg value

* fix: generate only for SPA

* chore: explain to use nuxt static X

* fix: render SPA fallback on redirect for static target

* fix: lint issue

* fix: only target is useful for now

* wip

* wip: nuxt static export is looking good

* Update packages/generator/src/generator.js

Co-Authored-By: Devon Rueckner <indirectlylit@users.noreply.github.com>

* Update packages/cli/src/options/common.js

Co-Authored-By: Alexander Lichter <manniL@gmx.net>

* feat: add options.target

* fix(lint): lint

* fix(test): update snapshots

* fix(builder): default value for target

* fix(test): fix test

* fix(test): test fixing

* fix: use this.options.target

* fix: final test

* Update packages/vue-renderer/src/renderer.js

Co-Authored-By: Alexander Lichter <manniL@gmx.net>

* feat: Add target option and update banner

* fix(lint): fix

* feat: Add warning when using serverMiddleware in static target

* chore(utils): add TARGETS and MODES as constants

* hotfix: lint

* chore(module): add filename as alias of fileName

* feat: introducing nuxt export and router/routes.json

* hotfix: Fix the linting lord

* chore(core): add comment for filename vs fileName

* fix: use targets constant

* chore: remove warning

* fix: unit testing

* wip: refactor and use TARGETS

* fix: lint

* feat: add target as alias for first arg value

* chore: explain to use nuxt static X

* fix: render SPA fallback on redirect for static target

* fix: lint issue

* fix: only target is useful for now

* wip

* wip: nuxt static export is looking good

* Update packages/generator/src/generator.js

Co-Authored-By: Devon Rueckner <indirectlylit@users.noreply.github.com>

* Update packages/cli/src/options/common.js

Co-Authored-By: Alexander Lichter <manniL@gmx.net>

* fix: duplicate imports

* chore: don't server render if an error happens on static target

* test: update unit and add export

* lint: fix

* lint: fix

* fix: e2e test

* fix: fallback only for static target

* fix: dev test

* feat: add generate.crawler

* fix: full static is when generate.static is given

* chore: improvements

* fix: Add isFullStatic in nuxt/config.json

* feat: handle fetch for full static

* feat: router.prefetchPayloads for full static

* chore: use fetch in async-data example

* fix: add target only if given

* fix: use created to have access to props in fetchOnServer

* chore: add console.error in dev for easy debugging

* feat: payload smart pre-fetching

* fix: remove alias for target

* fix: increment payloadFetchIndex is static set to false

* chore: lint

* chore: add serve command

* chore: rename universal to server-side

* fix: handle payloadPath on SPA fallback

* fix: lint

* chore lint again

* feat: handle spa fallback

* feat: support string for exclude

* fix: fallback only if no extension or html

* chore: use JSON.stringify() for static target

* chore: lint again, dammit

* chore: fix tests and remove too early return

* fix: early return only for server target

* fix: update tests

* fix: unit tests

* chore: add ssr option

* chore: add logic for ssr option

* fix: #6682

* chore(dx): add next command to run

* fix: lint

* fix: tests

* chore: keep old behaviour for nuxt build in spa

* fix: test again, oh boy

* fix: alright this is good now

* chore: add comment for spa fallback

* chore: move routes.json to dot nuxt dir

* chore: simplify check for promise

* chore: unique lock id

* chore: refactor isFullStatic

* fix: dont set default in build context

* chore: add test for serve

* chore: update tests

* hotfix: lint tests

* chore(dx): improve message for bundling

* feat: js payload extraction with jsonp

* fix: keep serialized session script for legacy generate

* fix: call to setPagePayload from fetchPayload

* use devalue for payload chunks

* feat: add initial load state chunk

* feat: preload payload and state scripts

* fix(vue-app): don't re-render the app if trailing slash on SSG

* hotfix: remove console.log

* chore(dx): add deploy infos for nuxt export

Co-authored-by: Pooya Parsa <pyapar@gmail.com>

* chore: handle fetching payload.js for nuxt state

* chore(dx): error when using nuxt generate and static

* chore: remove static option for clarity

* chore: remove serverless target

* hotfix: lint

* hotfix: unit tests

* chore: update legacy js resource

* chore: remove query params from url in static target

* fix: use globalName and urlJoin

* chore: typo

* feat: previewMode 👀

* chore: rename to enablePreview

* fix: wait next tick to avoid error on spa

* chore: try 1 sec

* hotfix: test only for linux, wtf azure

* refactor: static assets

- generalize logic for modules need emit export static assets
- allow customization for version, dir and base
- serialization logic is only in ssr now

* feat: smart state chunk creates

* fix(client): ignore payload load error

* perf: avoide payload loading for spa initial

* perf: avoid loading failed chunks again

* chore(cli): add simple compression for nuxt serve

* test: update snapshots

* fix version snapshot

* fix(generator): set staticAssetsBase on context only for full static

* fix tests

* fix: honor shouldHashCspScriptSrc

* chore(dx): add log for client-side fallback creation

Co-authored-by: Xin Du (Clark) <clark.duxin@gmail.com>
Co-authored-by: Alexander Lichter <manniL@gmx.net>
Co-authored-by: Pooya Parsa <pooya@pi0.ir>
Co-authored-by: Devon Rueckner <indirectlylit@users.noreply.github.com>
Co-authored-by: Pooya Parsa <pyapar@gmail.com>
2020-05-07 21:08:01 +02:00

230 lines
8.1 KiB
JavaScript

import path from 'path'
import consola from 'consola'
import fsExtra from 'fs-extra'
import { flatRoutes, isString, isUrl, promisifyRoute } from '@nuxt/utils'
import Generator from '../src/generator'
import { createNuxt } from './__utils__'
jest.mock('path')
jest.mock('fs-extra')
jest.mock('@nuxt/utils')
describe('generator: initialize', () => {
beforeAll(() => {
isString.mockImplementation(str => typeof str === 'string')
path.join.mockImplementation((...args) => `join(${args.join(', ')})`)
path.resolve.mockImplementation((...args) => `resolve(${args.join(', ')})`)
})
beforeEach(() => {
jest.clearAllMocks()
})
test('should construct Generator', () => {
isUrl.mockReturnValueOnce(true)
const nuxt = createNuxt()
nuxt.options = {
...nuxt.options,
build: { publicPath: 'http://localhost:3000' }
}
const builder = jest.fn()
const generator = new Generator(nuxt, builder)
expect(generator.nuxt).toBe(nuxt)
expect(generator.options).toBe(nuxt.options)
expect(generator.builder).toBe(builder)
expect(generator.staticRoutes).toEqual('resolve(/var/nuxt/src, /var/nuxt/static)')
expect(generator.srcBuiltPath).toBe('resolve(/var/nuxt/build, dist, client)')
expect(generator.distPath).toBe('/var/nuxt/generate')
expect(generator.distNuxtPath).toBe('join(/var/nuxt/generate, )')
})
test('should append publicPath to distPath if publicPath is not url', () => {
isUrl.mockReturnValueOnce(false)
const nuxt = createNuxt()
nuxt.options = {
...nuxt.options,
build: { publicPath: '__public' }
}
const builder = jest.fn()
const generator = new Generator(nuxt, builder)
expect(generator.distNuxtPath).toBe('join(/var/nuxt/generate, __public)')
})
test('should initiate with build and init by default', async () => {
const nuxt = createNuxt()
const builder = { forGenerate: jest.fn(), build: jest.fn() }
const generator = new Generator(nuxt, builder)
generator.initDist = jest.fn()
await generator.initiate()
expect(nuxt.ready).toBeCalledTimes(1)
expect(nuxt.callHook).toBeCalledTimes(1)
expect(nuxt.callHook).toBeCalledWith('generate:before', generator, { dir: generator.distPath })
expect(builder.forGenerate).toBeCalledTimes(1)
expect(builder.build).toBeCalledTimes(1)
expect(generator.initDist).toBeCalledTimes(1)
})
test('should initiate without build and init if disabled', async () => {
const nuxt = createNuxt()
const builder = { forGenerate: jest.fn(), build: jest.fn() }
const generator = new Generator(nuxt, builder)
generator.initDist = jest.fn()
fsExtra.exists.mockReturnValueOnce(true)
generator.getBuildConfig = jest.fn(() => ({ ssr: true, target: 'static' }))
await generator.initiate({ build: false, init: false })
expect(nuxt.ready).toBeCalledTimes(1)
expect(nuxt.callHook).toBeCalledTimes(1)
expect(nuxt.callHook).toBeCalledWith('generate:before', generator, { dir: generator.distPath })
expect(builder.forGenerate).not.toBeCalled()
expect(builder.build).not.toBeCalled()
expect(generator.initDist).not.toBeCalled()
})
test('should init routes with generate.routes and routes.json', async () => {
const nuxt = createNuxt()
nuxt.options = {
...nuxt.options,
generate: {
...nuxt.options.generate,
exclude: [/test/],
routes: ['/foo', '/foo/bar']
},
router: {
mode: 'history'
}
}
const generator = new Generator(nuxt)
flatRoutes.mockImplementationOnce(routes => routes)
promisifyRoute.mockImplementationOnce(routes => routes)
generator.getAppRoutes = jest.fn(() => ['/index', '/about', '/test'])
generator.decorateWithPayloads = jest.fn(() => 'decoratedRoutes')
const routes = await generator.initRoutes()
expect(promisifyRoute).toBeCalledTimes(1)
expect(promisifyRoute).toBeCalledWith(['/foo', '/foo/bar'])
expect(flatRoutes).toBeCalledTimes(1)
expect(flatRoutes).toBeCalledWith(['/index', '/about', '/test'])
expect(generator.decorateWithPayloads).toBeCalledTimes(1)
expect(generator.decorateWithPayloads).toBeCalledWith(['/index', '/about'], ['/foo', '/foo/bar'])
expect(nuxt.callHook).toBeCalledTimes(1)
expect(nuxt.callHook).toBeCalledWith('generate:extendRoutes', 'decoratedRoutes')
expect(routes).toEqual('decoratedRoutes')
})
test('should init routes with hash mode', async () => {
const nuxt = createNuxt()
nuxt.options = {
...nuxt.options,
generate: {
...nuxt.options.generate,
exclude: [/test/],
routes: ['/foo', '/foo/bar']
},
router: {
mode: 'hash'
}
}
const generator = new Generator(nuxt)
flatRoutes.mockImplementationOnce(routes => routes)
promisifyRoute.mockImplementationOnce(routes => routes)
generator.decorateWithPayloads = jest.fn(() => 'decoratedRoutes')
const routes = await generator.initRoutes()
expect(promisifyRoute).not.toBeCalled()
expect(flatRoutes).not.toBeCalled()
expect(generator.decorateWithPayloads).toBeCalledTimes(1)
expect(generator.decorateWithPayloads).toBeCalledWith(['/'], [])
expect(nuxt.callHook).toBeCalledTimes(1)
expect(nuxt.callHook).toBeCalledWith('generate:extendRoutes', 'decoratedRoutes')
expect(routes).toEqual('decoratedRoutes')
promisifyRoute.mockReset()
flatRoutes.mockReset()
})
test('should throw error when route can not be resolved', async () => {
const nuxt = createNuxt()
nuxt.options.router = { mode: 'history' }
const generator = new Generator(nuxt)
promisifyRoute.mockImplementationOnce(() => {
throw new Error('promisifyRoute failed')
})
await expect(generator.initRoutes()).rejects.toThrow('promisifyRoute failed')
expect(promisifyRoute).toBeCalledTimes(1)
expect(promisifyRoute).toBeCalledWith([])
expect(consola.error).toBeCalledTimes(1)
expect(consola.error).toBeCalledWith('Could not resolve routes')
})
test('should initialize destination folder', async () => {
const nuxt = createNuxt()
nuxt.options.generate.fallback = 'fallback.html'
const generator = new Generator(nuxt)
path.join.mockClear()
path.resolve.mockClear()
fsExtra.exists.mockReturnValueOnce(false)
await generator.initDist()
expect(fsExtra.remove).toBeCalledTimes(1)
expect(fsExtra.remove).toBeCalledWith(generator.distPath)
expect(nuxt.callHook).toBeCalledTimes(2)
expect(nuxt.callHook).nthCalledWith(1, 'generate:distRemoved', generator)
expect(fsExtra.exists).toBeCalledTimes(1)
expect(fsExtra.exists).toBeCalledWith(generator.staticRoutes)
expect(fsExtra.copy).toBeCalledTimes(1)
expect(fsExtra.copy).toBeCalledWith(generator.srcBuiltPath, generator.distNuxtPath)
expect(path.resolve).toBeCalledTimes(1)
expect(path.resolve).toBeCalledWith(generator.distPath, '.nojekyll')
expect(fsExtra.writeFile).toBeCalledTimes(1)
expect(fsExtra.writeFile).toBeCalledWith(`resolve(${generator.distPath}, .nojekyll)`, '')
expect(nuxt.callHook).nthCalledWith(2, 'generate:distCopied', generator)
})
test('should copy static routes if path exists', async () => {
const nuxt = createNuxt()
nuxt.options.generate.fallback = 'fallback.html'
const generator = new Generator(nuxt)
fsExtra.exists.mockReturnValueOnce(true)
await generator.initDist()
expect(fsExtra.copy).toBeCalledTimes(2)
expect(fsExtra.copy).nthCalledWith(1, generator.staticRoutes, generator.distPath)
expect(fsExtra.copy).nthCalledWith(2, generator.srcBuiltPath, generator.distNuxtPath)
})
test('should decorate routes with payloads', () => {
const nuxt = createNuxt()
const generator = new Generator(nuxt)
const routes = ['/index', '/about', '/test']
const generateRoutes = ['/foo', { route: '/foo/bar', payload: { param: 'foo bar' } }]
const routeMap = generator.decorateWithPayloads(routes, generateRoutes)
expect(routeMap).toEqual([
{ payload: null, route: '/index' },
{ payload: null, route: '/about' },
{ payload: null, route: '/test' },
{ payload: null, route: '/foo' },
{ payload: { param: 'foo bar' }, route: '/foo/bar' }
])
})
})