mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-27 08:02:01 +00:00
style: format with prettier
This commit is contained in:
parent
b3e9952976
commit
10d1b5974c
@ -11,7 +11,15 @@ const webpackDevMiddleware = require('webpack-dev-middleware')
|
||||
const webpackHotMiddleware = require('webpack-hot-middleware')
|
||||
const Debug = require('debug')
|
||||
const Glob = require('glob')
|
||||
const { r, wp, wChunk, createRoutes, sequence, relativeTo, waitFor } = require('../common/utils')
|
||||
const {
|
||||
r,
|
||||
wp,
|
||||
wChunk,
|
||||
createRoutes,
|
||||
sequence,
|
||||
relativeTo,
|
||||
waitFor
|
||||
} = require('../common/utils')
|
||||
const { Options } = require('../common')
|
||||
const clientWebpackConfig = require('./webpack/client.config.js')
|
||||
const serverWebpackConfig = require('./webpack/server.config.js')
|
||||
@ -41,7 +49,8 @@ module.exports = class Builder {
|
||||
this.webpackStats = this.options.dev ? false : this.options.build.stats
|
||||
|
||||
// Helper to resolve build paths
|
||||
this.relativeToBuild = (...args) => relativeTo(this.options.buildDir, ...args)
|
||||
this.relativeToBuild = (...args) =>
|
||||
relativeTo(this.options.buildDir, ...args)
|
||||
|
||||
this._buildStatus = STATUS.INITIAL
|
||||
|
||||
@ -56,28 +65,34 @@ module.exports = class Builder {
|
||||
}
|
||||
|
||||
get plugins() {
|
||||
return _.uniqBy(this.options.plugins.map((p, i) => {
|
||||
if (typeof p === 'string') p = { src: p }
|
||||
const pluginBaseName = basename(p.src, extname(p.src)).replace(/[^a-zA-Z?\d\s:]/g, '')
|
||||
return {
|
||||
src: this.nuxt.resolveAlias(p.src),
|
||||
ssr: (p.ssr !== false),
|
||||
name: 'nuxt_plugin_' + pluginBaseName + '_' + hash(p.src)
|
||||
}
|
||||
}), p => p.name)
|
||||
return _.uniqBy(
|
||||
this.options.plugins.map((p, i) => {
|
||||
if (typeof p === 'string') p = { src: p }
|
||||
const pluginBaseName = basename(p.src, extname(p.src)).replace(
|
||||
/[^a-zA-Z?\d\s:]/g,
|
||||
''
|
||||
)
|
||||
return {
|
||||
src: this.nuxt.resolveAlias(p.src),
|
||||
ssr: p.ssr !== false,
|
||||
name: 'nuxt_plugin_' + pluginBaseName + '_' + hash(p.src)
|
||||
}
|
||||
}),
|
||||
p => p.name
|
||||
)
|
||||
}
|
||||
|
||||
vendor() {
|
||||
return [
|
||||
'vue',
|
||||
'vue-router',
|
||||
'vue-meta',
|
||||
this.options.store && 'vuex'
|
||||
].concat(this.options.build.extractCSS && [
|
||||
// https://github.com/webpack-contrib/extract-text-webpack-plugin/issues/456
|
||||
'vue-style-loader/lib/addStylesClient',
|
||||
'css-loader/lib/css-base'
|
||||
]).concat(this.options.build.vendor).filter(v => v)
|
||||
return ['vue', 'vue-router', 'vue-meta', this.options.store && 'vuex']
|
||||
.concat(
|
||||
this.options.build.extractCSS && [
|
||||
// https://github.com/webpack-contrib/extract-text-webpack-plugin/issues/456
|
||||
'vue-style-loader/lib/addStylesClient',
|
||||
'css-loader/lib/css-base'
|
||||
]
|
||||
)
|
||||
.concat(this.options.build.vendor)
|
||||
.filter(v => v)
|
||||
}
|
||||
|
||||
vendorEntries() {
|
||||
@ -87,7 +102,7 @@ module.exports = class Builder {
|
||||
vendor.forEach(v => {
|
||||
try {
|
||||
require.resolve(v)
|
||||
vendorEntries[v] = [ v ]
|
||||
vendorEntries[v] = [v]
|
||||
} catch (e) {
|
||||
// Ignore
|
||||
}
|
||||
@ -125,9 +140,13 @@ module.exports = class Builder {
|
||||
if (!existsSync(join(this.options.srcDir, 'pages'))) {
|
||||
let dir = this.options.srcDir
|
||||
if (existsSync(join(this.options.srcDir, '..', 'pages'))) {
|
||||
throw new Error(`No \`pages\` directory found in ${dir}. Did you mean to run \`nuxt\` in the parent (\`../\`) directory?`)
|
||||
throw new Error(
|
||||
`No \`pages\` directory found in ${dir}. Did you mean to run \`nuxt\` in the parent (\`../\`) directory?`
|
||||
)
|
||||
} else {
|
||||
throw new Error(`Couldn't find a \`pages\` directory in ${dir}. Please create one under the project root`)
|
||||
throw new Error(
|
||||
`Couldn't find a \`pages\` directory in ${dir}. Please create one under the project root`
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -158,10 +177,14 @@ module.exports = class Builder {
|
||||
}
|
||||
|
||||
getBabelOptions({ isServer }) {
|
||||
const options = _.defaults({}, {
|
||||
babelrc: false,
|
||||
cacheDirectory: !!this.options.dev
|
||||
}, this.options.build.babel)
|
||||
const options = _.defaults(
|
||||
{},
|
||||
{
|
||||
babelrc: false,
|
||||
cacheDirectory: !!this.options.dev
|
||||
},
|
||||
this.options.build.babel
|
||||
)
|
||||
|
||||
if (typeof options.presets === 'function') {
|
||||
options.presets = options.presets({ isServer })
|
||||
@ -216,7 +239,9 @@ module.exports = class Builder {
|
||||
]
|
||||
const templateVars = {
|
||||
options: this.options,
|
||||
extensions: this.options.extensions.map((ext) => ext.replace(/^\./, '')).join('|'),
|
||||
extensions: this.options.extensions
|
||||
.map(ext => ext.replace(/^\./, ''))
|
||||
.join('|'),
|
||||
messages: this.options.messages,
|
||||
uniqBy: _.uniqBy,
|
||||
isDev: this.options.dev,
|
||||
@ -232,30 +257,48 @@ module.exports = class Builder {
|
||||
appPath: './App.js',
|
||||
ignorePrefix: this.options.ignorePrefix,
|
||||
layouts: Object.assign({}, this.options.layouts),
|
||||
loading: typeof this.options.loading === 'string' ? this.relativeToBuild(this.options.srcDir, this.options.loading) : this.options.loading,
|
||||
loading:
|
||||
typeof this.options.loading === 'string'
|
||||
? this.relativeToBuild(this.options.srcDir, this.options.loading)
|
||||
: this.options.loading,
|
||||
transition: this.options.transition,
|
||||
layoutTransition: this.options.layoutTransition,
|
||||
components: {
|
||||
ErrorPage: this.options.ErrorPage ? this.relativeToBuild(this.options.ErrorPage) : null
|
||||
ErrorPage: this.options.ErrorPage
|
||||
? this.relativeToBuild(this.options.ErrorPage)
|
||||
: null
|
||||
}
|
||||
}
|
||||
|
||||
// -- Layouts --
|
||||
if (existsSync(resolve(this.options.srcDir, 'layouts'))) {
|
||||
const layoutsFiles = await glob('layouts/**/*.{vue,js}', { cwd: this.options.srcDir, ignore: [`layouts/**/${this.options.ignorePrefix}*.{vue,js}`] })
|
||||
const layoutsFiles = await glob('layouts/**/*.{vue,js}', {
|
||||
cwd: this.options.srcDir,
|
||||
ignore: [`layouts/**/${this.options.ignorePrefix}*.{vue,js}`]
|
||||
})
|
||||
let hasErrorLayout = false
|
||||
layoutsFiles.forEach((file) => {
|
||||
let name = file.split('/').slice(1).join('/').replace(/\.(vue|js)$/, '')
|
||||
layoutsFiles.forEach(file => {
|
||||
let name = file
|
||||
.split('/')
|
||||
.slice(1)
|
||||
.join('/')
|
||||
.replace(/\.(vue|js)$/, '')
|
||||
if (name === 'error') {
|
||||
hasErrorLayout = true
|
||||
return
|
||||
}
|
||||
if (!templateVars.layouts[name] || /\.vue$/.test(file)) {
|
||||
templateVars.layouts[name] = this.relativeToBuild(this.options.srcDir, file)
|
||||
templateVars.layouts[name] = this.relativeToBuild(
|
||||
this.options.srcDir,
|
||||
file
|
||||
)
|
||||
}
|
||||
})
|
||||
if (!templateVars.components.ErrorPage && hasErrorLayout) {
|
||||
templateVars.components.ErrorPage = this.relativeToBuild(this.options.srcDir, 'layouts/error.vue')
|
||||
templateVars.components.ErrorPage = this.relativeToBuild(
|
||||
this.options.srcDir,
|
||||
'layouts/error.vue'
|
||||
)
|
||||
}
|
||||
}
|
||||
// If no default layout, create its folder and add the default folder
|
||||
@ -270,24 +313,39 @@ module.exports = class Builder {
|
||||
// If user defined a custom method to create routes
|
||||
if (this._nuxtPages) {
|
||||
// Use nuxt.js createRoutes bases on pages/
|
||||
const files = {};
|
||||
(await glob('pages/**/*.{vue,js}', { cwd: this.options.srcDir, ignore: [`pages/**/${this.options.ignorePrefix}*.{vue,js}`] })).forEach(f => {
|
||||
const files = {}
|
||||
;(await glob('pages/**/*.{vue,js}', {
|
||||
cwd: this.options.srcDir,
|
||||
ignore: [`pages/**/${this.options.ignorePrefix}*.{vue,js}`]
|
||||
})).forEach(f => {
|
||||
const key = f.replace(/\.(js|vue)$/, '')
|
||||
if (/\.vue$/.test(f) || !files[key]) {
|
||||
files[key] = f
|
||||
}
|
||||
})
|
||||
templateVars.router.routes = createRoutes(Object.values(files), this.options.srcDir)
|
||||
templateVars.router.routes = createRoutes(
|
||||
Object.values(files),
|
||||
this.options.srcDir
|
||||
)
|
||||
} else {
|
||||
templateVars.router.routes = this.options.build.createRoutes(this.options.srcDir)
|
||||
templateVars.router.routes = this.options.build.createRoutes(
|
||||
this.options.srcDir
|
||||
)
|
||||
}
|
||||
|
||||
await this.nuxt.callHook('build:extendRoutes', templateVars.router.routes, r)
|
||||
await this.nuxt.callHook(
|
||||
'build:extendRoutes',
|
||||
templateVars.router.routes,
|
||||
r
|
||||
)
|
||||
|
||||
// router.extendRoutes method
|
||||
if (typeof this.options.router.extendRoutes === 'function') {
|
||||
// let the user extend the routes
|
||||
const extendedRoutes = this.options.router.extendRoutes(templateVars.router.routes, r)
|
||||
const extendedRoutes = this.options.router.extendRoutes(
|
||||
templateVars.router.routes,
|
||||
r
|
||||
)
|
||||
// Only overwrite routes when something is returned for backwards compatibility
|
||||
if (extendedRoutes !== undefined) {
|
||||
templateVars.router.routes = extendedRoutes
|
||||
@ -304,41 +362,56 @@ module.exports = class Builder {
|
||||
}
|
||||
|
||||
// Resolve template files
|
||||
const customTemplateFiles = this.options.build.templates.map(t => t.dst || basename(t.src || t))
|
||||
const customTemplateFiles = this.options.build.templates.map(
|
||||
t => t.dst || basename(t.src || t)
|
||||
)
|
||||
|
||||
templatesFiles = templatesFiles.map(file => {
|
||||
// Skip if custom file was already provided in build.templates[]
|
||||
if (customTemplateFiles.indexOf(file) !== -1) {
|
||||
return
|
||||
}
|
||||
// Allow override templates using a file with same name in ${srcDir}/app
|
||||
const customPath = r(this.options.srcDir, 'app', file)
|
||||
const customFileExists = existsSync(customPath)
|
||||
templatesFiles = templatesFiles
|
||||
.map(file => {
|
||||
// Skip if custom file was already provided in build.templates[]
|
||||
if (customTemplateFiles.indexOf(file) !== -1) {
|
||||
return
|
||||
}
|
||||
// Allow override templates using a file with same name in ${srcDir}/app
|
||||
const customPath = r(this.options.srcDir, 'app', file)
|
||||
const customFileExists = existsSync(customPath)
|
||||
|
||||
return {
|
||||
src: customFileExists
|
||||
? customPath
|
||||
: r(this.options.nuxtAppDir, file),
|
||||
dst: file,
|
||||
custom: customFileExists
|
||||
}
|
||||
}).filter(i => !!i)
|
||||
return {
|
||||
src: customFileExists ? customPath : r(this.options.nuxtAppDir, file),
|
||||
dst: file,
|
||||
custom: customFileExists
|
||||
}
|
||||
})
|
||||
.filter(i => !!i)
|
||||
|
||||
// -- Custom templates --
|
||||
// Add custom template files
|
||||
templatesFiles = templatesFiles.concat(this.options.build.templates.map(t => {
|
||||
return Object.assign({
|
||||
src: r(this.options.srcDir, t.src || t),
|
||||
dst: t.dst || basename(t.src || t),
|
||||
custom: true
|
||||
}, t)
|
||||
}))
|
||||
templatesFiles = templatesFiles.concat(
|
||||
this.options.build.templates.map(t => {
|
||||
return Object.assign(
|
||||
{
|
||||
src: r(this.options.srcDir, t.src || t),
|
||||
dst: t.dst || basename(t.src || t),
|
||||
custom: true
|
||||
},
|
||||
t
|
||||
)
|
||||
})
|
||||
)
|
||||
|
||||
// -- Loading indicator --
|
||||
if (this.options.loadingIndicator.name) {
|
||||
const indicatorPath1 = resolve(this.options.nuxtAppDir, 'views/loading', this.options.loadingIndicator.name + '.html')
|
||||
const indicatorPath2 = this.nuxt.resolveAlias(this.options.loadingIndicator.name)
|
||||
const indicatorPath = existsSync(indicatorPath1) ? indicatorPath1 : (existsSync(indicatorPath2) ? indicatorPath2 : null)
|
||||
const indicatorPath1 = resolve(
|
||||
this.options.nuxtAppDir,
|
||||
'views/loading',
|
||||
this.options.loadingIndicator.name + '.html'
|
||||
)
|
||||
const indicatorPath2 = this.nuxt.resolveAlias(
|
||||
this.options.loadingIndicator.name
|
||||
)
|
||||
const indicatorPath = existsSync(indicatorPath1)
|
||||
? indicatorPath1
|
||||
: existsSync(indicatorPath2) ? indicatorPath2 : null
|
||||
if (indicatorPath) {
|
||||
templatesFiles.push({
|
||||
src: indicatorPath,
|
||||
@ -347,48 +420,61 @@ module.exports = class Builder {
|
||||
})
|
||||
} else {
|
||||
/* istanbul ignore next */
|
||||
console.error(`Could not fetch loading indicator: ${this.options.loadingIndicator.name}`) // eslint-disable-line no-console
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(
|
||||
`Could not fetch loading indicator: ${
|
||||
this.options.loadingIndicator.name
|
||||
}`
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
await this.nuxt.callHook('build:templates', { templatesFiles, templateVars, resolve: r })
|
||||
await this.nuxt.callHook('build:templates', {
|
||||
templatesFiles,
|
||||
templateVars,
|
||||
resolve: r
|
||||
})
|
||||
|
||||
// Interpret and move template files to .nuxt/
|
||||
await Promise.all(templatesFiles.map(async ({ src, dst, options, custom }) => {
|
||||
// Add template to watchers
|
||||
this.options.build.watch.push(src)
|
||||
// Render template to dst
|
||||
const fileContent = await readFile(src, 'utf8')
|
||||
let content
|
||||
try {
|
||||
const template = _.template(fileContent, {
|
||||
imports: {
|
||||
serialize,
|
||||
hash,
|
||||
r,
|
||||
wp,
|
||||
wChunk,
|
||||
resolvePath: this.nuxt.resolvePath.bind(this.nuxt),
|
||||
resolveAlias: this.nuxt.resolveAlias.bind(this.nuxt),
|
||||
relativeToBuild: this.relativeToBuild
|
||||
}
|
||||
})
|
||||
content = template(Object.assign({}, templateVars, {
|
||||
options: options || {},
|
||||
custom,
|
||||
src,
|
||||
dst
|
||||
}))
|
||||
} catch (err) {
|
||||
/* istanbul ignore next */
|
||||
throw new Error(`Could not compile template ${src}: ${err.message}`)
|
||||
}
|
||||
const path = r(this.options.buildDir, dst)
|
||||
// Ensure parent dir exits
|
||||
await mkdirp(dirname(path))
|
||||
// Write file
|
||||
await writeFile(path, content, 'utf8')
|
||||
}))
|
||||
await Promise.all(
|
||||
templatesFiles.map(async ({ src, dst, options, custom }) => {
|
||||
// Add template to watchers
|
||||
this.options.build.watch.push(src)
|
||||
// Render template to dst
|
||||
const fileContent = await readFile(src, 'utf8')
|
||||
let content
|
||||
try {
|
||||
const template = _.template(fileContent, {
|
||||
imports: {
|
||||
serialize,
|
||||
hash,
|
||||
r,
|
||||
wp,
|
||||
wChunk,
|
||||
resolvePath: this.nuxt.resolvePath.bind(this.nuxt),
|
||||
resolveAlias: this.nuxt.resolveAlias.bind(this.nuxt),
|
||||
relativeToBuild: this.relativeToBuild
|
||||
}
|
||||
})
|
||||
content = template(
|
||||
Object.assign({}, templateVars, {
|
||||
options: options || {},
|
||||
custom,
|
||||
src,
|
||||
dst
|
||||
})
|
||||
)
|
||||
} catch (err) {
|
||||
/* istanbul ignore next */
|
||||
throw new Error(`Could not compile template ${src}: ${err.message}`)
|
||||
}
|
||||
const path = r(this.options.buildDir, dst)
|
||||
// Ensure parent dir exits
|
||||
await mkdirp(dirname(path))
|
||||
// Write file
|
||||
await writeFile(path, content, 'utf8')
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
async webpackBuild() {
|
||||
@ -443,77 +529,101 @@ module.exports = class Builder {
|
||||
})
|
||||
|
||||
// Start Builds
|
||||
await sequence(this.compilers, (compiler) => new Promise(async (resolve, reject) => {
|
||||
const name = compiler.options.name
|
||||
await this.nuxt.callHook('build:compile', { name, compiler })
|
||||
await sequence(
|
||||
this.compilers,
|
||||
compiler =>
|
||||
new Promise(async (resolve, reject) => {
|
||||
const name = compiler.options.name
|
||||
await this.nuxt.callHook('build:compile', { name, compiler })
|
||||
|
||||
// Resolve only when compiler emit done event
|
||||
compiler.plugin('done', async (stats) => {
|
||||
await this.nuxt.callHook('build:compiled', { name, compiler, stats })
|
||||
// Reload renderer if available
|
||||
this.nuxt.renderer.loadResources(sharedFS || require('fs'))
|
||||
// Resolve on next tick
|
||||
process.nextTick(resolve)
|
||||
})
|
||||
// --- Dev Build ---
|
||||
if (this.options.dev) {
|
||||
// Client Build, watch is started by dev-middleware
|
||||
if (compiler.options.name === 'client') {
|
||||
return this.webpackDev(compiler)
|
||||
}
|
||||
// DLL build, should run only once
|
||||
if (compiler.options.name.includes('-dll')) {
|
||||
// Resolve only when compiler emit done event
|
||||
compiler.plugin('done', async stats => {
|
||||
await this.nuxt.callHook('build:compiled', {
|
||||
name,
|
||||
compiler,
|
||||
stats
|
||||
})
|
||||
// Reload renderer if available
|
||||
this.nuxt.renderer.loadResources(sharedFS || require('fs'))
|
||||
// Resolve on next tick
|
||||
process.nextTick(resolve)
|
||||
})
|
||||
// --- Dev Build ---
|
||||
if (this.options.dev) {
|
||||
// Client Build, watch is started by dev-middleware
|
||||
if (compiler.options.name === 'client') {
|
||||
return this.webpackDev(compiler)
|
||||
}
|
||||
// DLL build, should run only once
|
||||
if (compiler.options.name.includes('-dll')) {
|
||||
compiler.run((err, stats) => {
|
||||
if (err) return reject(err)
|
||||
debug('[DLL] updated')
|
||||
})
|
||||
return
|
||||
}
|
||||
// Server, build and watch for changes
|
||||
this.compilersWatching.push(
|
||||
compiler.watch(this.options.watchers.webpack, err => {
|
||||
/* istanbul ignore if */
|
||||
if (err) return reject(err)
|
||||
})
|
||||
)
|
||||
return
|
||||
}
|
||||
// --- Production Build ---
|
||||
compiler.run((err, stats) => {
|
||||
if (err) return reject(err)
|
||||
debug('[DLL] updated')
|
||||
})
|
||||
return
|
||||
}
|
||||
// Server, build and watch for changes
|
||||
this.compilersWatching.push(
|
||||
compiler.watch(this.options.watchers.webpack, (err) => {
|
||||
/* istanbul ignore if */
|
||||
if (err) return reject(err)
|
||||
if (err) {
|
||||
console.error(err) // eslint-disable-line no-console
|
||||
return reject(err)
|
||||
}
|
||||
|
||||
// Show build stats for production
|
||||
console.log(stats.toString(this.webpackStats)) // eslint-disable-line no-console
|
||||
|
||||
/* istanbul ignore if */
|
||||
if (stats.hasErrors()) {
|
||||
return reject(new Error('Webpack build exited with errors'))
|
||||
}
|
||||
})
|
||||
)
|
||||
return
|
||||
}
|
||||
// --- Production Build ---
|
||||
compiler.run((err, stats) => {
|
||||
/* istanbul ignore if */
|
||||
if (err) {
|
||||
console.error(err) // eslint-disable-line no-console
|
||||
return reject(err)
|
||||
}
|
||||
|
||||
// Show build stats for production
|
||||
console.log(stats.toString(this.webpackStats)) // eslint-disable-line no-console
|
||||
|
||||
/* istanbul ignore if */
|
||||
if (stats.hasErrors()) {
|
||||
return reject(new Error('Webpack build exited with errors'))
|
||||
}
|
||||
})
|
||||
}))
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
webpackDev(compiler) {
|
||||
debug('Adding webpack middleware...')
|
||||
|
||||
// Create webpack dev middleware
|
||||
this.webpackDevMiddleware = promisify(webpackDevMiddleware(compiler, Object.assign({
|
||||
publicPath: this.options.build.publicPath,
|
||||
stats: this.webpackStats,
|
||||
logLevel: 'silent',
|
||||
watchOptions: this.options.watchers.webpack
|
||||
}, this.options.build.devMiddleware)))
|
||||
this.webpackDevMiddleware = promisify(
|
||||
webpackDevMiddleware(
|
||||
compiler,
|
||||
Object.assign(
|
||||
{
|
||||
publicPath: this.options.build.publicPath,
|
||||
stats: this.webpackStats,
|
||||
logLevel: 'silent',
|
||||
watchOptions: this.options.watchers.webpack
|
||||
},
|
||||
this.options.build.devMiddleware
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
this.webpackDevMiddleware.close = promisify(this.webpackDevMiddleware.close)
|
||||
|
||||
this.webpackHotMiddleware = promisify(webpackHotMiddleware(compiler, Object.assign({
|
||||
log: false,
|
||||
heartbeat: 10000
|
||||
}, this.options.build.hotMiddleware)))
|
||||
this.webpackHotMiddleware = promisify(
|
||||
webpackHotMiddleware(
|
||||
compiler,
|
||||
Object.assign(
|
||||
{
|
||||
log: false,
|
||||
heartbeat: 10000
|
||||
},
|
||||
this.options.build.hotMiddleware
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
// Inject to renderer instance
|
||||
if (this.nuxt.renderer) {
|
||||
@ -550,13 +660,17 @@ module.exports = class Builder {
|
||||
const refreshFiles = _.debounce(() => this.generateRoutesAndFiles(), 200)
|
||||
|
||||
// Watch for src Files
|
||||
this.filesWatcher = chokidar.watch(patterns, options)
|
||||
this.filesWatcher = chokidar
|
||||
.watch(patterns, options)
|
||||
.on('add', refreshFiles)
|
||||
.on('unlink', refreshFiles)
|
||||
|
||||
// Watch for custom provided files
|
||||
const watchFiles = _.map(_.uniq(this.options.build.watch), p => upath.normalizeSafe(p))
|
||||
this.customFilesWatcher = chokidar.watch(watchFiles, options)
|
||||
const watchFiles = _.map(_.uniq(this.options.build.watch), p =>
|
||||
upath.normalizeSafe(p)
|
||||
)
|
||||
this.customFilesWatcher = chokidar
|
||||
.watch(watchFiles, options)
|
||||
.on('change', refreshFiles)
|
||||
}
|
||||
|
||||
@ -578,7 +692,11 @@ module.exports = class Builder {
|
||||
async generateConfig() {
|
||||
const config = resolve(this.options.buildDir, 'build.config.js')
|
||||
const options = _.omit(this.options, Options.unsafeKeys)
|
||||
await writeFile(config, `module.exports = ${JSON.stringify(options, null, ' ')}`, 'utf8')
|
||||
await writeFile(
|
||||
config,
|
||||
`module.exports = ${JSON.stringify(options, null, ' ')}`,
|
||||
'utf8'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -11,6 +11,7 @@ const { resolve } = require('path')
|
||||
const { existsSync } = require('fs')
|
||||
const Debug = require('debug')
|
||||
const Chalk = require('chalk')
|
||||
const { printWarn } = require('../../common/utils')
|
||||
const base = require('./base.config.js')
|
||||
|
||||
const debug = Debug('nuxt:build')
|
||||
@ -43,7 +44,10 @@ module.exports = function webpackClientConfig() {
|
||||
// Env object defined in nuxt.config.js
|
||||
let env = {}
|
||||
each(this.options.env, (value, key) => {
|
||||
env['process.env.' + key] = (['boolean', 'number'].indexOf(typeof value) !== -1 ? value : JSON.stringify(value))
|
||||
env['process.env.' + key] =
|
||||
['boolean', 'number'].indexOf(typeof value) !== -1
|
||||
? value
|
||||
: JSON.stringify(value)
|
||||
})
|
||||
|
||||
// Generate output HTML for SPA
|
||||
@ -85,36 +89,47 @@ module.exports = function webpackClientConfig() {
|
||||
|
||||
// Define Env
|
||||
config.plugins.push(
|
||||
new webpack.DefinePlugin(Object.assign(env, {
|
||||
'process.env.NODE_ENV': JSON.stringify(env.NODE_ENV || (this.options.dev ? 'development' : 'production')),
|
||||
'process.env.VUE_ENV': JSON.stringify('client'),
|
||||
'process.mode': JSON.stringify(this.options.mode),
|
||||
'process.browser': true,
|
||||
'process.client': true,
|
||||
'process.server': false,
|
||||
'process.static': this.isStatic
|
||||
}))
|
||||
new webpack.DefinePlugin(
|
||||
Object.assign(env, {
|
||||
'process.env.NODE_ENV': JSON.stringify(
|
||||
env.NODE_ENV || (this.options.dev ? 'development' : 'production')
|
||||
),
|
||||
'process.env.VUE_ENV': JSON.stringify('client'),
|
||||
'process.mode': JSON.stringify(this.options.mode),
|
||||
'process.browser': true,
|
||||
'process.client': true,
|
||||
'process.server': false,
|
||||
'process.static': this.isStatic
|
||||
})
|
||||
)
|
||||
)
|
||||
|
||||
// Build progress bar
|
||||
if (this.options.build.profile) {
|
||||
config.plugins.push(new ProgressPlugin({
|
||||
profile: true
|
||||
}))
|
||||
config.plugins.push(
|
||||
new ProgressPlugin({
|
||||
profile: true
|
||||
})
|
||||
)
|
||||
} else {
|
||||
config.plugins.push(new ProgressBarPlugin({
|
||||
complete: Chalk.green('█'),
|
||||
incomplete: Chalk.white('█'),
|
||||
format: ' :bar ' + Chalk.green.bold(':percent') + ' :msg',
|
||||
clear: false
|
||||
}))
|
||||
config.plugins.push(
|
||||
new ProgressBarPlugin({
|
||||
complete: Chalk.green('█'),
|
||||
incomplete: Chalk.white('█'),
|
||||
format: ' :bar ' + Chalk.green.bold(':percent') + ' :msg',
|
||||
clear: false
|
||||
})
|
||||
)
|
||||
}
|
||||
|
||||
const shouldClearConsole = this.options.build.stats !== false &&
|
||||
this.options.build.stats !== 'errors-only'
|
||||
const shouldClearConsole =
|
||||
this.options.build.stats !== false &&
|
||||
this.options.build.stats !== 'errors-only'
|
||||
|
||||
// Add friendly error plugin
|
||||
config.plugins.push(new FriendlyErrorsWebpackPlugin({ clearConsole: shouldClearConsole }))
|
||||
config.plugins.push(
|
||||
new FriendlyErrorsWebpackPlugin({ clearConsole: shouldClearConsole })
|
||||
)
|
||||
|
||||
// --------------------------------------
|
||||
// Dev specific config
|
||||
@ -126,7 +141,9 @@ module.exports = function webpackClientConfig() {
|
||||
// Add HMR support
|
||||
config.entry.app = [
|
||||
// https://github.com/glenjamin/webpack-hot-middleware#config
|
||||
`webpack-hot-middleware/client?name=client&reload=true&timeout=30000&path=${this.options.router.base}/__webpack_hmr`.replace(/\/\//g, '/'),
|
||||
`webpack-hot-middleware/client?name=client&reload=true&timeout=30000&path=${
|
||||
this.options.router.base
|
||||
}/__webpack_hmr`.replace(/\/\//g, '/'),
|
||||
config.entry.app
|
||||
]
|
||||
config.plugins.push(
|
||||
@ -156,25 +173,32 @@ module.exports = function webpackClientConfig() {
|
||||
// https://github.com/webpack-contrib/uglifyjs-webpack-plugin
|
||||
if (this.options.build.uglify !== false) {
|
||||
config.plugins.push(
|
||||
new UglifyJSPlugin(Object.assign({
|
||||
// cache: true,
|
||||
sourceMap: true,
|
||||
parallel: true,
|
||||
extractComments: {
|
||||
filename: 'LICENSES'
|
||||
},
|
||||
uglifyOptions: {
|
||||
output: {
|
||||
comments: /^\**!|@preserve|@license|@cc_on/
|
||||
}
|
||||
}
|
||||
}, this.options.build.uglify))
|
||||
new UglifyJSPlugin(
|
||||
Object.assign(
|
||||
{
|
||||
// cache: true,
|
||||
sourceMap: true,
|
||||
parallel: true,
|
||||
extractComments: {
|
||||
filename: 'LICENSES'
|
||||
},
|
||||
uglifyOptions: {
|
||||
output: {
|
||||
comments: /^\**!|@preserve|@license|@cc_on/
|
||||
}
|
||||
}
|
||||
},
|
||||
this.options.build.uglify
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// Webpack Bundle Analyzer
|
||||
if (this.options.build.analyze) {
|
||||
config.plugins.push(new BundleAnalyzerPlugin(Object.assign({}, this.options.build.analyze)))
|
||||
config.plugins.push(
|
||||
new BundleAnalyzerPlugin(Object.assign({}, this.options.build.analyze))
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@ -183,7 +207,7 @@ module.exports = function webpackClientConfig() {
|
||||
const isDev = this.options.dev
|
||||
const extendedConfig = this.options.build.extend.call(this, config, {
|
||||
get dev() {
|
||||
console.warn('dev has been deprecated in build.extend(), please use isDev') // eslint-disable-line no-console
|
||||
printWarn('dev has been deprecated in build.extend(), please use isDev')
|
||||
return isDev
|
||||
},
|
||||
isDev,
|
||||
|
@ -2,9 +2,11 @@ module.exports = class WarnFixPlugin {
|
||||
apply(compiler) /* istanbul ignore next */ {
|
||||
compiler.plugin('done', stats => {
|
||||
stats.compilation.warnings = stats.compilation.warnings.filter(warn => {
|
||||
if (warn.name === 'ModuleDependencyWarning' &&
|
||||
if (
|
||||
warn.name === 'ModuleDependencyWarning' &&
|
||||
warn.message.includes(`export 'default'`) &&
|
||||
warn.message.includes('nuxt_plugin_')) {
|
||||
warn.message.includes('nuxt_plugin_')
|
||||
) {
|
||||
return false
|
||||
}
|
||||
return true
|
||||
|
@ -14,7 +14,13 @@ module.exports = function postcssConfig() {
|
||||
// Search for postCSS config file and use it if exists
|
||||
// https://github.com/michael-ciniawsky/postcss-load-config
|
||||
for (let dir of [this.options.srcDir, this.options.rootDir]) {
|
||||
for (let file of ['postcss.config.js', '.postcssrc.js', '.postcssrc', '.postcssrc.json', '.postcssrc.yaml']) {
|
||||
for (let file of [
|
||||
'postcss.config.js',
|
||||
'.postcssrc.js',
|
||||
'.postcssrc',
|
||||
'.postcssrc.json',
|
||||
'.postcssrc.yaml'
|
||||
]) {
|
||||
if (existsSync(resolve(dir, file))) {
|
||||
const postcssConfigPath = resolve(dir, file)
|
||||
return {
|
||||
@ -34,27 +40,30 @@ module.exports = function postcssConfig() {
|
||||
|
||||
// Apply default plugins
|
||||
if (isPureObject(config)) {
|
||||
config = Object.assign({
|
||||
useConfigFile: false,
|
||||
sourceMap: this.options.build.cssSourceMap,
|
||||
plugins: {
|
||||
// https://github.com/postcss/postcss-import
|
||||
'postcss-import': {
|
||||
root: this.options.rootDir,
|
||||
path: [
|
||||
this.options.srcDir,
|
||||
this.options.rootDir,
|
||||
...this.options.modulesDir
|
||||
]
|
||||
},
|
||||
config = Object.assign(
|
||||
{
|
||||
useConfigFile: false,
|
||||
sourceMap: this.options.build.cssSourceMap,
|
||||
plugins: {
|
||||
// https://github.com/postcss/postcss-import
|
||||
'postcss-import': {
|
||||
root: this.options.rootDir,
|
||||
path: [
|
||||
this.options.srcDir,
|
||||
this.options.rootDir,
|
||||
...this.options.modulesDir
|
||||
]
|
||||
},
|
||||
|
||||
// https://github.com/postcss/postcss-url
|
||||
'postcss-url': {},
|
||||
// https://github.com/postcss/postcss-url
|
||||
'postcss-url': {},
|
||||
|
||||
// http://cssnext.io/postcss
|
||||
'postcss-cssnext': {}
|
||||
}
|
||||
}, config)
|
||||
// http://cssnext.io/postcss
|
||||
'postcss-cssnext': {}
|
||||
}
|
||||
},
|
||||
config
|
||||
)
|
||||
}
|
||||
|
||||
// Map postcss plugins into instances on object mode once
|
||||
@ -66,7 +75,8 @@ module.exports = function postcssConfig() {
|
||||
if (opts === false) return // Disabled
|
||||
const instance = plugin(opts)
|
||||
return instance
|
||||
}).filter(e => e)
|
||||
})
|
||||
.filter(e => e)
|
||||
}
|
||||
|
||||
return config
|
||||
|
@ -4,6 +4,7 @@ const nodeExternals = require('webpack-node-externals')
|
||||
const { each } = require('lodash')
|
||||
const { resolve } = require('path')
|
||||
const { existsSync } = require('fs')
|
||||
const { printWarn } = require('../../common/utils')
|
||||
const base = require('./base.config.js')
|
||||
|
||||
/*
|
||||
@ -17,7 +18,10 @@ module.exports = function webpackServerConfig() {
|
||||
// Env object defined in nuxt.config.js
|
||||
let env = {}
|
||||
each(this.options.env, (value, key) => {
|
||||
env['process.env.' + key] = (['boolean', 'number'].indexOf(typeof value) !== -1 ? value : JSON.stringify(value))
|
||||
env['process.env.' + key] =
|
||||
['boolean', 'number'].indexOf(typeof value) !== -1
|
||||
? value
|
||||
: JSON.stringify(value)
|
||||
})
|
||||
|
||||
// Config devtool
|
||||
@ -40,15 +44,19 @@ module.exports = function webpackServerConfig() {
|
||||
new VueSSRServerPlugin({
|
||||
filename: 'server-bundle.json'
|
||||
}),
|
||||
new webpack.DefinePlugin(Object.assign(env, {
|
||||
'process.env.NODE_ENV': JSON.stringify(env.NODE_ENV || (this.options.dev ? 'development' : 'production')),
|
||||
'process.env.VUE_ENV': JSON.stringify('server'),
|
||||
'process.mode': JSON.stringify(this.options.mode),
|
||||
'process.browser': false,
|
||||
'process.client': false,
|
||||
'process.server': true,
|
||||
'process.static': this.isStatic
|
||||
}))
|
||||
new webpack.DefinePlugin(
|
||||
Object.assign(env, {
|
||||
'process.env.NODE_ENV': JSON.stringify(
|
||||
env.NODE_ENV || (this.options.dev ? 'development' : 'production')
|
||||
),
|
||||
'process.env.VUE_ENV': JSON.stringify('server'),
|
||||
'process.mode': JSON.stringify(this.options.mode),
|
||||
'process.browser': false,
|
||||
'process.client': false,
|
||||
'process.server': true,
|
||||
'process.static': this.isStatic
|
||||
})
|
||||
)
|
||||
])
|
||||
})
|
||||
|
||||
@ -56,11 +64,13 @@ module.exports = function webpackServerConfig() {
|
||||
// https://github.com/liady/webpack-node-externals
|
||||
this.options.modulesDir.forEach(dir => {
|
||||
if (existsSync(dir)) {
|
||||
config.externals.push(nodeExternals({
|
||||
// load non-javascript files with extensions, presumably via loaders
|
||||
whitelist: [/es6-promise|\.(?!(?:js|json)$).{1,5}$/i],
|
||||
modulesDir: dir
|
||||
}))
|
||||
config.externals.push(
|
||||
nodeExternals({
|
||||
// load non-javascript files with extensions, presumably via loaders
|
||||
whitelist: [/es6-promise|\.(?!(?:js|json)$).{1,5}$/i],
|
||||
modulesDir: dir
|
||||
})
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
@ -69,7 +79,7 @@ module.exports = function webpackServerConfig() {
|
||||
const isDev = this.options.dev
|
||||
const extendedConfig = this.options.build.extend.call(this, config, {
|
||||
get dev() {
|
||||
console.warn('dev has been deprecated in build.extend(), please use isDev') // eslint-disable-line no-console
|
||||
printWarn('dev has been deprecated in build.extend(), please use isDev')
|
||||
return isDev
|
||||
},
|
||||
isDev,
|
||||
|
@ -6,8 +6,12 @@ module.exports = function styleLoader(ext, loaders = [], isVueLoader = false) {
|
||||
const sourceMap = Boolean(this.options.build.cssSourceMap)
|
||||
|
||||
// Normalize loaders
|
||||
loaders = (Array.isArray(loaders) ? loaders : [loaders])
|
||||
.map(loader => Object.assign({ options: { sourceMap } }, typeof loader === 'string' ? { loader } : loader))
|
||||
loaders = (Array.isArray(loaders) ? loaders : [loaders]).map(loader =>
|
||||
Object.assign(
|
||||
{ options: { sourceMap } },
|
||||
typeof loader === 'string' ? { loader } : loader
|
||||
)
|
||||
)
|
||||
|
||||
// Prepare vue-style-loader
|
||||
// https://github.com/vuejs/vue-style-loader
|
||||
@ -21,8 +25,14 @@ module.exports = function styleLoader(ext, loaders = [], isVueLoader = false) {
|
||||
// style-resources-loader
|
||||
// https://github.com/yenshih/style-resources-loader
|
||||
if (this.options.build.styleResources[ext]) {
|
||||
const patterns = Array.isArray(this.options.build.styleResources[ext]) ? this.options.build.styleResources[ext] : [ this.options.build.styleResources[ext] ]
|
||||
const options = Object.assign({}, (this.options.build.styleResources.options || {}), { patterns })
|
||||
const patterns = Array.isArray(this.options.build.styleResources[ext])
|
||||
? this.options.build.styleResources[ext]
|
||||
: [this.options.build.styleResources[ext]]
|
||||
const options = Object.assign(
|
||||
{},
|
||||
this.options.build.styleResources.options || {},
|
||||
{ patterns }
|
||||
)
|
||||
|
||||
loaders.push({
|
||||
loader: 'style-resources-loader',
|
||||
@ -77,9 +87,9 @@ module.exports = function styleLoader(ext, loaders = [], isVueLoader = false) {
|
||||
options: { sourceMap }
|
||||
}
|
||||
|
||||
return this.options.dev ? [ hotLoader ].concat(extractLoader) : extractLoader
|
||||
return this.options.dev ? [hotLoader].concat(extractLoader) : extractLoader
|
||||
}
|
||||
|
||||
// -- Without extractCSS --
|
||||
return [ vueStyleLoader ].concat(loaders)
|
||||
return [vueStyleLoader].concat(loaders)
|
||||
}
|
||||
|
@ -9,17 +9,22 @@ module.exports = function vueLoader({ isServer }) {
|
||||
cssSourceMap: this.options.build.cssSourceMap,
|
||||
preserveWhitespace: false,
|
||||
loaders: {
|
||||
'js': {
|
||||
js: {
|
||||
loader: 'babel-loader',
|
||||
options: this.getBabelOptions({ isServer })
|
||||
},
|
||||
// Note: do not nest the `postcss` option under `loaders`
|
||||
'css': styleLoader.call(this, 'css', [], true),
|
||||
'less': styleLoader.call(this, 'less', 'less-loader', true),
|
||||
'scss': styleLoader.call(this, 'scss', 'sass-loader', true),
|
||||
'sass': styleLoader.call(this, 'sass', {loader: 'sass-loader', options: { indentedSyntax: true }}, true),
|
||||
'stylus': styleLoader.call(this, 'stylus', 'stylus-loader', true),
|
||||
'styl': styleLoader.call(this, 'stylus', 'stylus-loader', true)
|
||||
css: styleLoader.call(this, 'css', [], true),
|
||||
less: styleLoader.call(this, 'less', 'less-loader', true),
|
||||
scss: styleLoader.call(this, 'scss', 'sass-loader', true),
|
||||
sass: styleLoader.call(
|
||||
this,
|
||||
'sass',
|
||||
{ loader: 'sass-loader', options: { indentedSyntax: true } },
|
||||
true
|
||||
),
|
||||
stylus: styleLoader.call(this, 'stylus', 'stylus-loader', true),
|
||||
styl: styleLoader.call(this, 'stylus', 'stylus-loader', true)
|
||||
},
|
||||
template: {
|
||||
doctype: 'html' // For pug, see https://github.com/vuejs/vue-loader/issues/55
|
||||
|
@ -19,7 +19,11 @@ Options.from = function (_options) {
|
||||
if (options.loading === true) {
|
||||
delete options.loading
|
||||
}
|
||||
if (options.router && options.router.middleware && !Array.isArray(options.router.middleware)) {
|
||||
if (
|
||||
options.router &&
|
||||
options.router.middleware &&
|
||||
!Array.isArray(options.router.middleware)
|
||||
) {
|
||||
options.router.middleware = [options.router.middleware]
|
||||
}
|
||||
if (options.router && typeof options.router.base === 'string') {
|
||||
@ -32,7 +36,7 @@ Options.from = function (_options) {
|
||||
options.layoutTransition = { name: options.layoutTransition }
|
||||
}
|
||||
if (typeof options.extensions === 'string') {
|
||||
options.extensions = [ options.extensions ]
|
||||
options.extensions = [options.extensions]
|
||||
}
|
||||
|
||||
const hasValue = v => typeof v === 'string' && v
|
||||
@ -50,7 +54,9 @@ Options.from = function (_options) {
|
||||
_.defaultsDeep(options, Options.defaults)
|
||||
|
||||
// Resolve dirs
|
||||
options.srcDir = hasValue(options.srcDir) ? resolve(options.rootDir, options.srcDir) : options.rootDir
|
||||
options.srcDir = hasValue(options.srcDir)
|
||||
? resolve(options.rootDir, options.srcDir)
|
||||
: options.rootDir
|
||||
options.buildDir = resolve(options.rootDir, options.buildDir)
|
||||
options.cacheDir = resolve(options.rootDir, options.cacheDir)
|
||||
|
||||
@ -94,11 +100,14 @@ Options.from = function (_options) {
|
||||
}
|
||||
|
||||
// Apply defaults to loadingIndicator
|
||||
options.loadingIndicator = Object.assign({
|
||||
name: 'pulse',
|
||||
color: '#dbe1ec',
|
||||
background: 'white'
|
||||
}, options.loadingIndicator)
|
||||
options.loadingIndicator = Object.assign(
|
||||
{
|
||||
name: 'pulse',
|
||||
color: '#dbe1ec',
|
||||
background: 'white'
|
||||
},
|
||||
options.loadingIndicator
|
||||
)
|
||||
|
||||
// cssSourceMap
|
||||
if (options.build.cssSourceMap === undefined) {
|
||||
@ -111,7 +120,8 @@ Options.from = function (_options) {
|
||||
}
|
||||
|
||||
// Apply mode preset
|
||||
let modePreset = Options.modes[options.mode || 'universal'] || Options.modes['universal']
|
||||
let modePreset =
|
||||
Options.modes[options.mode || 'universal'] || Options.modes['universal']
|
||||
_.defaultsDeep(options, modePreset)
|
||||
|
||||
// If no server-side rendering, add appear true transition
|
||||
@ -299,9 +309,11 @@ Options.defaults = {
|
||||
server_error: 'Server error',
|
||||
nuxtjs: 'Nuxt.js',
|
||||
back_to_home: 'Back to the home page',
|
||||
server_error_details: 'An error occurred in the application and your page could not be served. If you are the application owner, check your logs for details.',
|
||||
server_error_details:
|
||||
'An error occurred in the application and your page could not be served. If you are the application owner, check your logs for details.',
|
||||
client_error: 'Error',
|
||||
client_error_details: 'An error occurred while rendering the page. Check developer tools console for details.',
|
||||
client_error_details:
|
||||
'An error occurred while rendering the page. Check developer tools console for details.',
|
||||
redirect: 'Redirecting to external page.'
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,3 @@
|
||||
|
||||
const Vue = require('vue')
|
||||
const VueMeta = require('vue-meta')
|
||||
const VueServerRenderer = require('vue-server-renderer')
|
||||
@ -51,7 +50,13 @@ module.exports = class MetaRenderer {
|
||||
// BODY_ATTRS
|
||||
meta.BODY_ATTRS = m.bodyAttrs.text()
|
||||
// HEAD tags
|
||||
meta.HEAD = m.meta.text() + m.title.text() + m.link.text() + m.style.text() + m.script.text() + m.noscript.text()
|
||||
meta.HEAD =
|
||||
m.meta.text() +
|
||||
m.title.text() +
|
||||
m.link.text() +
|
||||
m.style.text() +
|
||||
m.script.text() +
|
||||
m.noscript.text()
|
||||
// BODY_SCRIPTS
|
||||
meta.BODY_SCRIPTS = m.script.text({ body: true })
|
||||
// Resources Hints
|
||||
@ -62,11 +67,17 @@ module.exports = class MetaRenderer {
|
||||
const publicPath = clientManifest.publicPath || '/_nuxt/'
|
||||
// Pre-Load initial resources
|
||||
if (Array.isArray(clientManifest.initial)) {
|
||||
meta.resourceHints += clientManifest.initial.map(r => `<link rel="preload" href="${publicPath}${r}" as="script" />`).join('')
|
||||
meta.resourceHints += clientManifest.initial
|
||||
.map(
|
||||
r => `<link rel="preload" href="${publicPath}${r}" as="script" />`
|
||||
)
|
||||
.join('')
|
||||
}
|
||||
// Pre-Fetch async resources
|
||||
if (Array.isArray(clientManifest.async)) {
|
||||
meta.resourceHints += clientManifest.async.map(r => `<link rel="prefetch" href="${publicPath}${r}" />`).join('')
|
||||
meta.resourceHints += clientManifest.async
|
||||
.map(r => `<link rel="prefetch" href="${publicPath}${r}" />`)
|
||||
.join('')
|
||||
}
|
||||
// Add them to HEAD
|
||||
if (meta.resourceHints) {
|
||||
@ -75,12 +86,13 @@ module.exports = class MetaRenderer {
|
||||
}
|
||||
|
||||
// Emulate getPreloadFiles from vue-server-renderer (works for JS chunks only)
|
||||
meta.getPreloadFiles = () => clientManifest.initial.map(r => ({
|
||||
file: r,
|
||||
fileWithoutQuery: r,
|
||||
asType: 'script',
|
||||
extension: 'js'
|
||||
}))
|
||||
meta.getPreloadFiles = () =>
|
||||
clientManifest.initial.map(r => ({
|
||||
file: r,
|
||||
fileWithoutQuery: r,
|
||||
asType: 'script',
|
||||
extension: 'js'
|
||||
}))
|
||||
|
||||
// Set meta tags inside cache
|
||||
this.cache.set(url, meta)
|
||||
|
@ -6,7 +6,7 @@ module.exports = function errorMiddleware(err, req, res, next) {
|
||||
// ensure statusCode, message and name fields
|
||||
err.statusCode = err.statusCode || 500
|
||||
err.message = err.message || 'Nuxt Server Error'
|
||||
err.name = (!err.name || err.name === 'Error') ? 'NuxtServerError' : err.name
|
||||
err.name = !err.name || err.name === 'Error' ? 'NuxtServerError' : err.name
|
||||
|
||||
// We hide actual errors from end users, so show them on server logs
|
||||
if (err.statusCode !== 404) {
|
||||
@ -25,8 +25,11 @@ module.exports = function errorMiddleware(err, req, res, next) {
|
||||
}
|
||||
|
||||
// Check if request accepts JSON
|
||||
const hasReqHeader = (header, includes) => req.headers[header] && req.headers[header].toLowerCase().includes(includes)
|
||||
const isJson = hasReqHeader('accept', 'application/json') || hasReqHeader('user-agent', 'curl/')
|
||||
const hasReqHeader = (header, includes) =>
|
||||
req.headers[header] && req.headers[header].toLowerCase().includes(includes)
|
||||
const isJson =
|
||||
hasReqHeader('accept', 'application/json') ||
|
||||
hasReqHeader('user-agent', 'curl/')
|
||||
|
||||
// Use basic errors when debug mode is disabled
|
||||
if (!this.options.debug) {
|
||||
@ -46,17 +49,28 @@ module.exports = function errorMiddleware(err, req, res, next) {
|
||||
}
|
||||
|
||||
// Show stack trace
|
||||
const youch = new Youch(err, req, readSource.bind(this), this.options.router.base, true)
|
||||
const youch = new Youch(
|
||||
err,
|
||||
req,
|
||||
readSource.bind(this),
|
||||
this.options.router.base,
|
||||
true
|
||||
)
|
||||
if (isJson) {
|
||||
youch.toJSON().then(json => { sendResponse(JSON.stringify(json, undefined, 2), 'text/json') })
|
||||
youch.toJSON().then(json => {
|
||||
sendResponse(JSON.stringify(json, undefined, 2), 'text/json')
|
||||
})
|
||||
} else {
|
||||
youch.toHTML().then(html => { sendResponse(html) })
|
||||
youch.toHTML().then(html => {
|
||||
sendResponse(html)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async function readSource(frame) {
|
||||
// Remove webpack:/// & query string from the end
|
||||
const sanitizeName = name => name ? name.replace('webpack:///', '').split('?')[0] : null
|
||||
const sanitizeName = name =>
|
||||
name ? name.replace('webpack:///', '').split('?')[0] : null
|
||||
frame.fileName = sanitizeName(frame.fileName)
|
||||
|
||||
// Return if fileName is unknown
|
||||
|
@ -11,7 +11,13 @@ module.exports = async function nuxtMiddleware(req, res, next) {
|
||||
try {
|
||||
const result = await this.renderRoute(req.url, context)
|
||||
await this.nuxt.callHook('render:route', req.url, result)
|
||||
const { html, cspScriptSrcHashes, error, redirected, getPreloadFiles } = result
|
||||
const {
|
||||
html,
|
||||
cspScriptSrcHashes,
|
||||
error,
|
||||
redirected,
|
||||
getPreloadFiles
|
||||
} = result
|
||||
|
||||
if (redirected) {
|
||||
return html
|
||||
@ -62,7 +68,10 @@ module.exports = async function nuxtMiddleware(req, res, next) {
|
||||
}
|
||||
|
||||
if (this.options.render.csp) {
|
||||
res.setHeader('Content-Security-Policy', `script-src 'self' ${(cspScriptSrcHashes || []).join(' ')}`)
|
||||
res.setHeader(
|
||||
'Content-Security-Policy',
|
||||
`script-src 'self' ${(cspScriptSrcHashes || []).join(' ')}`
|
||||
)
|
||||
}
|
||||
|
||||
// Send response
|
||||
|
@ -94,14 +94,19 @@ module.exports = class Renderer {
|
||||
// Reload error template
|
||||
const errorTemplatePath = resolve(this.options.buildDir, 'views/error.html')
|
||||
if (fs.existsSync(errorTemplatePath)) {
|
||||
this.resources.errorTemplate = parseTemplate(fs.readFileSync(errorTemplatePath, 'utf8'))
|
||||
this.resources.errorTemplate = parseTemplate(
|
||||
fs.readFileSync(errorTemplatePath, 'utf8')
|
||||
)
|
||||
}
|
||||
|
||||
// Load loading template
|
||||
const loadingHTMLPath = resolve(this.options.buildDir, 'loading.html')
|
||||
if (fs.existsSync(loadingHTMLPath)) {
|
||||
this.resources.loadingHTML = fs.readFileSync(loadingHTMLPath, 'utf8')
|
||||
this.resources.loadingHTML = this.resources.loadingHTML.replace(/[\r|\n]/g, '')
|
||||
this.resources.loadingHTML = this.resources.loadingHTML.replace(
|
||||
/[\r|\n]/g,
|
||||
''
|
||||
)
|
||||
} else {
|
||||
this.resources.loadingHTML = ''
|
||||
}
|
||||
@ -157,11 +162,17 @@ module.exports = class Renderer {
|
||||
}
|
||||
|
||||
// Create bundle renderer for SSR
|
||||
this.bundleRenderer = createBundleRenderer(this.resources.serverBundle, Object.assign({
|
||||
clientManifest: this.resources.clientManifest,
|
||||
runInNewContext: false,
|
||||
basedir: this.options.rootDir
|
||||
}, this.options.render.bundleRenderer))
|
||||
this.bundleRenderer = createBundleRenderer(
|
||||
this.resources.serverBundle,
|
||||
Object.assign(
|
||||
{
|
||||
clientManifest: this.resources.clientManifest,
|
||||
runInNewContext: false,
|
||||
basedir: this.options.rootDir
|
||||
},
|
||||
this.options.render.bundleRenderer
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
useMiddleware(m) {
|
||||
@ -178,7 +189,10 @@ module.exports = class Renderer {
|
||||
}
|
||||
|
||||
const handler = m.handler || m
|
||||
const path = (((m.prefix !== false) ? this.options.router.base : '') + (typeof m.path === 'string' ? m.path : '')).replace(/\/\//g, '/')
|
||||
const path = (
|
||||
(m.prefix !== false ? this.options.router.base : '') +
|
||||
(typeof m.path === 'string' ? m.path : '')
|
||||
).replace(/\/\//g, '/')
|
||||
|
||||
// Inject $src and $m to final handler
|
||||
if (src) handler.$src = src
|
||||
@ -189,7 +203,9 @@ module.exports = class Renderer {
|
||||
}
|
||||
|
||||
get publicPath() {
|
||||
return isUrl(this.options.build.publicPath) ? Options.defaults.build.publicPath : this.options.build.publicPath
|
||||
return isUrl(this.options.build.publicPath)
|
||||
? Options.defaults.build.publicPath
|
||||
: this.options.build.publicPath
|
||||
}
|
||||
|
||||
async setupMiddleware() {
|
||||
@ -233,7 +249,12 @@ module.exports = class Renderer {
|
||||
}
|
||||
|
||||
// For serving static/ files to /
|
||||
this.useMiddleware(serveStatic(resolve(this.options.srcDir, 'static'), this.options.render.static))
|
||||
this.useMiddleware(
|
||||
serveStatic(
|
||||
resolve(this.options.srcDir, 'static'),
|
||||
this.options.render.static
|
||||
)
|
||||
)
|
||||
|
||||
// Serve .nuxt/dist/ files only for production
|
||||
// For dev they will be served with devMiddleware
|
||||
@ -280,12 +301,26 @@ module.exports = class Renderer {
|
||||
const ENV = this.options.env
|
||||
|
||||
if (this.noSSR || spa) {
|
||||
const { HTML_ATTRS, BODY_ATTRS, HEAD, BODY_SCRIPTS, getPreloadFiles } = await this.metaRenderer.render(context)
|
||||
const APP = `<div id="__nuxt">${this.resources.loadingHTML}</div>` + BODY_SCRIPTS
|
||||
const {
|
||||
HTML_ATTRS,
|
||||
BODY_ATTRS,
|
||||
HEAD,
|
||||
BODY_SCRIPTS,
|
||||
getPreloadFiles
|
||||
} = await this.metaRenderer.render(context)
|
||||
const APP =
|
||||
`<div id="__nuxt">${this.resources.loadingHTML}</div>` + BODY_SCRIPTS
|
||||
|
||||
// Detect 404 errors
|
||||
if (url.includes(this.options.build.publicPath) || url.includes('__webpack')) {
|
||||
const err = { statusCode: 404, message: this.options.messages.error_404, name: 'ResourceNotFound' }
|
||||
if (
|
||||
url.includes(this.options.build.publicPath) ||
|
||||
url.includes('__webpack')
|
||||
) {
|
||||
const err = {
|
||||
statusCode: 404,
|
||||
message: this.options.messages.error_404,
|
||||
name: 'ResourceNotFound'
|
||||
}
|
||||
throw err
|
||||
}
|
||||
|
||||
@ -307,7 +342,13 @@ module.exports = class Renderer {
|
||||
APP = '<div id="__nuxt"></div>'
|
||||
}
|
||||
const m = context.meta.inject()
|
||||
let HEAD = m.meta.text() + m.title.text() + m.link.text() + m.style.text() + m.script.text() + m.noscript.text()
|
||||
let HEAD =
|
||||
m.meta.text() +
|
||||
m.title.text() +
|
||||
m.link.text() +
|
||||
m.style.text() +
|
||||
m.script.text() +
|
||||
m.noscript.text()
|
||||
if (this.options._routerBaseSpecified) {
|
||||
HEAD += `<base href="${this.options.router.base}">`
|
||||
}
|
||||
@ -316,12 +357,16 @@ module.exports = class Renderer {
|
||||
HEAD += context.renderResourceHints()
|
||||
}
|
||||
|
||||
let serializedSession = `window.__NUXT__=${serialize(context.nuxt, { isJSON: true })};`
|
||||
let serializedSession = `window.__NUXT__=${serialize(context.nuxt, {
|
||||
isJSON: true
|
||||
})};`
|
||||
let cspScriptSrcHashes = []
|
||||
if (this.options.render.csp) {
|
||||
let hash = crypto.createHash(this.options.render.csp.hashAlgorithm)
|
||||
hash.update(serializedSession)
|
||||
cspScriptSrcHashes.push(`'${this.options.render.csp.hashAlgorithm}-${hash.digest('base64')}'`)
|
||||
cspScriptSrcHashes.push(
|
||||
`'${this.options.render.csp.hashAlgorithm}-${hash.digest('base64')}'`
|
||||
)
|
||||
}
|
||||
|
||||
APP += `<script type="text/javascript">${serializedSession}</script>`
|
||||
@ -375,7 +420,9 @@ module.exports = class Renderer {
|
||||
url = url || 'http://localhost:3000'
|
||||
const { window } = await jsdom.JSDOM.fromURL(url, options)
|
||||
// If Nuxt could not be loaded (error from the server-side)
|
||||
const nuxtExists = window.document.body.innerHTML.includes(this.options.render.ssr ? 'window.__NUXT__' : '<div id="__nuxt">')
|
||||
const nuxtExists = window.document.body.innerHTML.includes(
|
||||
this.options.render.ssr ? 'window.__NUXT__' : '<div id="__nuxt">'
|
||||
)
|
||||
/* istanbul ignore if */
|
||||
if (!nuxtExists) {
|
||||
let error = new Error('Could not load the nuxt app')
|
||||
@ -383,7 +430,7 @@ module.exports = class Renderer {
|
||||
throw error
|
||||
}
|
||||
// Used by nuxt.js to say when the components are loaded and the app ready
|
||||
await new Promise((resolve) => {
|
||||
await new Promise(resolve => {
|
||||
window._onNuxtLoaded = () => resolve(window)
|
||||
})
|
||||
// Send back window object
|
||||
@ -391,9 +438,10 @@ module.exports = class Renderer {
|
||||
}
|
||||
}
|
||||
|
||||
const parseTemplate = templateStr => _.template(templateStr, {
|
||||
interpolate: /{{([\s\S]+?)}}/g
|
||||
})
|
||||
const parseTemplate = templateStr =>
|
||||
_.template(templateStr, {
|
||||
interpolate: /{{([\s\S]+?)}}/g
|
||||
})
|
||||
|
||||
const resourceMap = [
|
||||
{
|
||||
@ -419,4 +467,7 @@ const resourceMap = [
|
||||
]
|
||||
|
||||
// Protector utility against request to SSR bundle files
|
||||
const ssrResourceRegex = new RegExp(resourceMap.map(resource => resource.fileName).join('|'), 'i')
|
||||
const ssrResourceRegex = new RegExp(
|
||||
resourceMap.map(resource => resource.fileName).join('|'),
|
||||
'i'
|
||||
)
|
||||
|
@ -20,7 +20,9 @@ const p = JSON.parse(originalPackage)
|
||||
p.name = 'nuxt-edge'
|
||||
|
||||
// Get latest git commit id
|
||||
const gitCommit = String(spawnSync('git', 'rev-parse --short HEAD'.split(' ')).stdout).trim()
|
||||
const gitCommit = String(
|
||||
spawnSync('git', 'rev-parse --short HEAD'.split(' ')).stdout
|
||||
).trim()
|
||||
|
||||
// Version with latest git commit id
|
||||
// Using date.now() so latest push will be always choosen by npm/yarn
|
||||
@ -32,7 +34,9 @@ p.version = `${baseVersion}-${date}.${gitCommit}`
|
||||
writeFileSync(packagePath, JSON.stringify(p, null, 2) + '\r\n')
|
||||
|
||||
// Parse git branch to decide npm tag
|
||||
let tag = String(spawnSync('git', 'rev-parse --abbrev-ref HEAD'.split(' ')).stdout).trim()
|
||||
let tag = String(
|
||||
spawnSync('git', 'rev-parse --abbrev-ref HEAD'.split(' ')).stdout
|
||||
).trim()
|
||||
|
||||
// dev ~> latest
|
||||
if (tag === 'dev') {
|
||||
@ -45,4 +49,6 @@ console.log(`publishing ${p.name}@${p.version} with tag ${tag}`)
|
||||
|
||||
// Do publish
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(String(spawnSync('npm', `publish --tag ${tag}`.split(' ')).stdout).trim())
|
||||
console.log(
|
||||
String(spawnSync('npm', `publish --tag ${tag}`.split(' ')).stdout).trim()
|
||||
)
|
||||
|
@ -2,7 +2,13 @@
|
||||
|
||||
const now = Date.now()
|
||||
|
||||
const { readFileSync, readJSONSync, writeFileSync, copySync, removeSync } = require('fs-extra')
|
||||
const {
|
||||
readFileSync,
|
||||
readJSONSync,
|
||||
writeFileSync,
|
||||
copySync,
|
||||
removeSync
|
||||
} = require('fs-extra')
|
||||
const { resolve } = require('path')
|
||||
|
||||
// Dirs
|
||||
@ -13,18 +19,11 @@ const startDir = resolve(rootDir, 'start')
|
||||
const packageJSON = readJSONSync(resolve(rootDir, 'package.json'))
|
||||
|
||||
// Required and Excluded packages for start
|
||||
let requires = [
|
||||
'source-map-support',
|
||||
'pretty-error',
|
||||
'minimist'
|
||||
]
|
||||
let requires = ['source-map-support', 'pretty-error', 'minimist']
|
||||
|
||||
const excludes = [
|
||||
'path',
|
||||
'fs',
|
||||
'http',
|
||||
'module'
|
||||
].concat(Object.keys(packageJSON.devDependencies))
|
||||
const excludes = ['path', 'fs', 'http', 'module'].concat(
|
||||
Object.keys(packageJSON.devDependencies)
|
||||
)
|
||||
|
||||
// Parse dist/core.js for all external dependencies
|
||||
const requireRegex = /require\('([-@/\w]+)'\)/g
|
||||
@ -66,13 +65,13 @@ packageJSON.bin = {
|
||||
}
|
||||
|
||||
// Update package.json
|
||||
writeFileSync(resolve(startDir, 'package.json'), JSON.stringify(packageJSON, null, 2))
|
||||
writeFileSync(
|
||||
resolve(startDir, 'package.json'),
|
||||
JSON.stringify(packageJSON, null, 2)
|
||||
)
|
||||
|
||||
// Copy required files
|
||||
const excludeFiles = [
|
||||
'README.md',
|
||||
'.gitignore'
|
||||
]
|
||||
const excludeFiles = ['README.md', '.gitignore']
|
||||
packageJSON.files.forEach(file => {
|
||||
if (excludeFiles.indexOf(file) !== -1) {
|
||||
return
|
||||
@ -99,11 +98,20 @@ extraFiles.forEach(file => {
|
||||
|
||||
// Patch index.js
|
||||
const startIndexjs = resolve(startDir, 'index.js')
|
||||
writeFileSync(startIndexjs, String(readFileSync(startIndexjs)).replace('./dist/nuxt', './dist/core'))
|
||||
writeFileSync(
|
||||
startIndexjs,
|
||||
String(readFileSync(startIndexjs)).replace('./dist/nuxt', './dist/core')
|
||||
)
|
||||
|
||||
// Patch bin/nuxt-start
|
||||
const binStart = resolve(startDir, 'bin/nuxt-start')
|
||||
writeFileSync(binStart, String(readFileSync(binStart)).replace(/nuxt start/g, 'nuxt-start'))
|
||||
writeFileSync(
|
||||
binStart,
|
||||
String(readFileSync(binStart)).replace(/nuxt start/g, 'nuxt-start')
|
||||
)
|
||||
|
||||
// eslint-disable-next-line no-console
|
||||
console.log(`Generated ${packageJSON.name}@${packageJSON.version} in ${Date.now() - now}ms`)
|
||||
console.log(
|
||||
`Generated ${packageJSON.name}@${packageJSON.version} in ${Date.now() -
|
||||
now}ms`
|
||||
)
|
||||
|
@ -5,7 +5,7 @@ import * as browser from './helpers/browser'
|
||||
import { interceptLog } from './helpers/console'
|
||||
|
||||
const port = 4003
|
||||
const url = (route) => 'http://localhost:' + port + route
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt = null
|
||||
let page = null
|
||||
@ -63,7 +63,10 @@ test.serial('/css', async t => {
|
||||
await page.nuxt.navigate('/css')
|
||||
|
||||
t.is(await page.$text('.red'), 'This is red')
|
||||
t.is(await page.$eval('.red', (red) => window.getComputedStyle(red).color), 'rgb(255, 0, 0)')
|
||||
t.is(
|
||||
await page.$eval('.red', red => window.getComputedStyle(red).color),
|
||||
'rgb(255, 0, 0)'
|
||||
)
|
||||
})
|
||||
|
||||
test.serial('/stateful', async t => {
|
||||
@ -80,7 +83,9 @@ test.serial('/store', async t => {
|
||||
})
|
||||
|
||||
test.serial('/head', async t => {
|
||||
const msg = new Promise((resolve) => page.on('console', (msg) => resolve(msg.text)))
|
||||
const msg = new Promise(resolve =>
|
||||
page.on('console', msg => resolve(msg.text))
|
||||
)
|
||||
await page.nuxt.navigate('/head')
|
||||
const metas = await page.$$attr('meta', 'content')
|
||||
|
||||
@ -158,7 +163,9 @@ test.serial('/redirect-external', async t => {
|
||||
// New page for redirecting to external link.
|
||||
const page = await browser.page(url('/'))
|
||||
await page.nuxt.navigate('/redirect-external', false)
|
||||
await page.waitForFunction(() => window.location.href === 'https://nuxtjs.org/')
|
||||
await page.waitForFunction(
|
||||
() => window.location.href === 'https://nuxtjs.org/'
|
||||
)
|
||||
page.close()
|
||||
t.pass()
|
||||
})
|
||||
@ -186,7 +193,10 @@ test.serial('/fn-midd', async t => {
|
||||
await page.nuxt.navigate('/fn-midd')
|
||||
|
||||
t.is(await page.$text('.title'), 'You need to ask the permission')
|
||||
t.deepEqual(await page.nuxt.errorData(), { message: 'You need to ask the permission', statusCode: 403 })
|
||||
t.deepEqual(await page.nuxt.errorData(), {
|
||||
message: 'You need to ask the permission',
|
||||
statusCode: 403
|
||||
})
|
||||
})
|
||||
|
||||
test.serial('/fn-midd?please=true', async t => {
|
||||
|
@ -4,7 +4,7 @@ import { intercept, release } from './helpers/console'
|
||||
import { Nuxt, Builder } from '..'
|
||||
|
||||
const port = 4001
|
||||
const url = (route) => 'http://localhost:' + port + route
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
const rootDir = resolve(__dirname, 'fixtures/basic')
|
||||
|
||||
let nuxt = null
|
||||
|
@ -22,10 +22,9 @@ test('Fail with routes() which throw an error', async t => {
|
||||
const builder = new Builder(nuxt)
|
||||
const generator = new Generator(nuxt, builder)
|
||||
|
||||
return generator.generate()
|
||||
.catch((e) => {
|
||||
t.true(e.message === 'Not today!')
|
||||
})
|
||||
return generator.generate().catch(e => {
|
||||
t.true(e.message === 'Not today!')
|
||||
})
|
||||
})
|
||||
t.true(spies.log.calledWithMatch('DONE'))
|
||||
t.true(spies.error.withArgs('Could not resolve routes').calledOnce)
|
||||
|
@ -10,7 +10,7 @@ import { interceptLog, release } from './helpers/console'
|
||||
import { Nuxt, Builder, Generator } from '..'
|
||||
|
||||
const port = 4002
|
||||
const url = (route) => 'http://localhost:' + port + route
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
const rootDir = resolve(__dirname, 'fixtures/basic')
|
||||
|
||||
let nuxt = null
|
||||
@ -91,7 +91,9 @@ test.serial('/async-data', async t => {
|
||||
test.serial('/users/1/index.html', async t => {
|
||||
const html = await rp(url('/users/1/index.html'))
|
||||
t.true(html.includes('<h1>User: 1</h1>'))
|
||||
t.true(existsSync(resolve(__dirname, 'fixtures/basic/dist', 'users/1/index.html')))
|
||||
t.true(
|
||||
existsSync(resolve(__dirname, 'fixtures/basic/dist', 'users/1/index.html'))
|
||||
)
|
||||
t.false(existsSync(resolve(__dirname, 'fixtures/basic/dist', 'users/1.html')))
|
||||
})
|
||||
|
||||
@ -160,7 +162,9 @@ test.serial('/users/1.html', async t => {
|
||||
const html = await rp(url('/users/1.html'))
|
||||
t.true(html.includes('<h1>User: 1</h1>'))
|
||||
t.true(existsSync(resolve(__dirname, 'fixtures/basic/dist', 'users/1.html')))
|
||||
t.false(existsSync(resolve(__dirname, 'fixtures/basic/dist', 'users/1/index.html')))
|
||||
t.false(
|
||||
existsSync(resolve(__dirname, 'fixtures/basic/dist', 'users/1/index.html'))
|
||||
)
|
||||
})
|
||||
|
||||
test.serial('/-ignored', async t => {
|
||||
|
@ -5,7 +5,7 @@ import { Nuxt, Builder } from '..'
|
||||
import { interceptLog, interceptError, release } from './helpers/console'
|
||||
|
||||
const port = 4004
|
||||
const url = (route) => 'http://localhost:' + port + route
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt = null
|
||||
|
||||
@ -83,12 +83,16 @@ test('/store', async t => {
|
||||
|
||||
test.serial('/head', async t => {
|
||||
const logSpy = await interceptLog()
|
||||
const window = await nuxt.renderAndGetWindow(url('/head'), { virtualConsole: false })
|
||||
const window = await nuxt.renderAndGetWindow(url('/head'), {
|
||||
virtualConsole: false
|
||||
})
|
||||
t.is(window.document.title, 'My title - Nuxt.js')
|
||||
|
||||
const html = window.document.body.innerHTML
|
||||
t.true(html.includes('<div><h1>I can haz meta tags</h1></div>'))
|
||||
t.true(html.includes('<script data-n-head="true" src="/body.js" data-body="true">'))
|
||||
t.true(
|
||||
html.includes('<script data-n-head="true" src="/body.js" data-body="true">')
|
||||
)
|
||||
|
||||
const metas = window.document.getElementsByTagName('meta')
|
||||
t.is(metas[0].getAttribute('content'), 'my meta')
|
||||
@ -169,7 +173,11 @@ test.serial('/error status code', async t => {
|
||||
const errorSpy = await interceptError()
|
||||
const err = await t.throws(rp(url('/error')))
|
||||
t.true(err.statusCode === 500)
|
||||
t.true(err.response.body.includes('An error occurred in the application and your page could not be served'))
|
||||
t.true(
|
||||
err.response.body.includes(
|
||||
'An error occurred in the application and your page could not be served'
|
||||
)
|
||||
)
|
||||
release()
|
||||
t.true(errorSpy.calledOnce)
|
||||
t.true(errorSpy.args[0][0].message.includes('Error mouahahah'))
|
||||
@ -215,7 +223,11 @@ test('/redirect-name', async t => {
|
||||
|
||||
test('/no-ssr', async t => {
|
||||
const { html } = await nuxt.renderRoute('/no-ssr')
|
||||
t.true(html.includes('<div class="no-ssr-placeholder"><p>Loading...</p></div>'))
|
||||
t.true(
|
||||
html.includes(
|
||||
'<div class="no-ssr-placeholder"><p>Loading...</p></div>'
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
test('/no-ssr (client-side)', async t => {
|
||||
@ -225,25 +237,38 @@ test('/no-ssr (client-side)', async t => {
|
||||
})
|
||||
|
||||
test('ETag Header', async t => {
|
||||
const { headers: { etag } } = await rp(url('/stateless'), { resolveWithFullResponse: true })
|
||||
const { headers: { etag } } = await rp(url('/stateless'), {
|
||||
resolveWithFullResponse: true
|
||||
})
|
||||
// Verify functionality
|
||||
const error = await t.throws(rp(url('/stateless'), { headers: { 'If-None-Match': etag } }))
|
||||
const error = await t.throws(
|
||||
rp(url('/stateless'), { headers: { 'If-None-Match': etag } })
|
||||
)
|
||||
t.is(error.statusCode, 304)
|
||||
})
|
||||
|
||||
test('Content-Security-Policy Header', async t => {
|
||||
const { headers } = await rp(url('/stateless'), { resolveWithFullResponse: true })
|
||||
const { headers } = await rp(url('/stateless'), {
|
||||
resolveWithFullResponse: true
|
||||
})
|
||||
// Verify functionality
|
||||
t.is(headers['content-security-policy'], "script-src 'self' 'sha256-BBvfKxDOoRM/gnFwke9u60HBZX3HUss/0lSI1sBRvOU='")
|
||||
t.is(
|
||||
headers['content-security-policy'],
|
||||
"script-src 'self' 'sha256-BBvfKxDOoRM/gnFwke9u60HBZX3HUss/0lSI1sBRvOU='"
|
||||
)
|
||||
})
|
||||
|
||||
test('/_nuxt/server-bundle.json should return 404', async t => {
|
||||
const err = await t.throws(rp(url('/_nuxt/server-bundle.json'), { resolveWithFullResponse: true }))
|
||||
const err = await t.throws(
|
||||
rp(url('/_nuxt/server-bundle.json'), { resolveWithFullResponse: true })
|
||||
)
|
||||
t.is(err.statusCode, 404)
|
||||
})
|
||||
|
||||
test('/_nuxt/ should return 404', async t => {
|
||||
const err = await t.throws(rp(url('/_nuxt/'), { resolveWithFullResponse: true }))
|
||||
const err = await t.throws(
|
||||
rp(url('/_nuxt/'), { resolveWithFullResponse: true })
|
||||
)
|
||||
t.is(err.statusCode, 404)
|
||||
})
|
||||
|
||||
@ -253,7 +278,9 @@ test('/meta', async t => {
|
||||
})
|
||||
|
||||
test('/fn-midd', async t => {
|
||||
const err = await t.throws(rp(url('/fn-midd'), { resolveWithFullResponse: true }))
|
||||
const err = await t.throws(
|
||||
rp(url('/fn-midd'), { resolveWithFullResponse: true })
|
||||
)
|
||||
t.is(err.statusCode, 403)
|
||||
t.true(err.response.body.includes('You need to ask the permission'))
|
||||
})
|
||||
|
@ -5,7 +5,7 @@ import * as browser from './helpers/browser'
|
||||
import { interceptLog } from './helpers/console'
|
||||
|
||||
const port = 4014
|
||||
const url = (route) => 'http://localhost:' + port + route
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt = null
|
||||
let page
|
||||
|
@ -5,7 +5,7 @@ import { Nuxt, Builder } from '..'
|
||||
import { interceptLog, interceptError, release } from './helpers/console'
|
||||
|
||||
const port = 4009
|
||||
const url = (route) => 'http://localhost:' + port + route
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt = null
|
||||
|
||||
@ -26,19 +26,32 @@ test.serial('Init Nuxt.js', async t => {
|
||||
})
|
||||
|
||||
test.serial('/test/__open-in-editor (open-in-editor)', async t => {
|
||||
const { body } = await rp(url('/test/__open-in-editor?file=pages/index.vue'), { resolveWithFullResponse: true })
|
||||
const { body } = await rp(
|
||||
url('/test/__open-in-editor?file=pages/index.vue'),
|
||||
{ resolveWithFullResponse: true }
|
||||
)
|
||||
t.is(body, '')
|
||||
})
|
||||
|
||||
test.serial('/test/__open-in-editor should return error (open-in-editor)', async t => {
|
||||
const { error, statusCode } = await t.throws(rp(url('/test/__open-in-editor?file='), { resolveWithFullResponse: true }))
|
||||
t.is(statusCode, 500)
|
||||
t.is(error, 'launch-editor-middleware: required query param "file" is missing.')
|
||||
})
|
||||
test.serial(
|
||||
'/test/__open-in-editor should return error (open-in-editor)',
|
||||
async t => {
|
||||
const { error, statusCode } = await t.throws(
|
||||
rp(url('/test/__open-in-editor?file='), { resolveWithFullResponse: true })
|
||||
)
|
||||
t.is(statusCode, 500)
|
||||
t.is(
|
||||
error,
|
||||
'launch-editor-middleware: required query param "file" is missing.'
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
test.serial('/test/error should return error stack trace (Youch)', async t => {
|
||||
const errorSpy = await interceptError()
|
||||
const { response, error } = await t.throws(nuxt.renderAndGetWindow(url('/test/error')))
|
||||
const { response, error } = await t.throws(
|
||||
nuxt.renderAndGetWindow(url('/test/error'))
|
||||
)
|
||||
t.is(response.statusCode, 500)
|
||||
t.is(response.statusMessage, 'NuxtServerError')
|
||||
t.true(error.includes('test youch !'))
|
||||
@ -54,7 +67,9 @@ test.serial('/test/error no source-map (Youch)', async t => {
|
||||
nuxt.renderer.resources.serverBundle.maps = {}
|
||||
|
||||
const errorSpy = await interceptError()
|
||||
const { response, error } = await t.throws(nuxt.renderAndGetWindow(url('/test/error')))
|
||||
const { response, error } = await t.throws(
|
||||
nuxt.renderAndGetWindow(url('/test/error'))
|
||||
)
|
||||
t.is(response.statusCode, 500)
|
||||
t.is(response.statusMessage, 'NuxtServerError')
|
||||
t.true(error.includes('test youch !'))
|
||||
@ -70,7 +85,7 @@ test.serial('/test/error no source-map (Youch)', async t => {
|
||||
test.serial('/test/error should return json format error (Youch)', async t => {
|
||||
const opts = {
|
||||
headers: {
|
||||
'accept': 'application/json'
|
||||
accept: 'application/json'
|
||||
},
|
||||
resolveWithFullResponse: true
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ import { Nuxt, Builder } from '..'
|
||||
import { intercept, interceptWarn, release } from './helpers/console'
|
||||
|
||||
const port = 4010
|
||||
const url = (route) => 'http://localhost:' + port + route
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt = null
|
||||
let builder = null
|
||||
@ -32,14 +32,26 @@ test.serial('Init Nuxt.js', async t => {
|
||||
test.serial('Deprecated: context.isServer and context.isClient', async t => {
|
||||
const warnSpy = await interceptWarn()
|
||||
await rp(url('/'))
|
||||
t.true(warnSpy.calledWith('context.isServer has been deprecated, please use process.server instead.'))
|
||||
t.true(warnSpy.calledWith('context.isClient has been deprecated, please use process.client instead.'))
|
||||
t.true(
|
||||
warnSpy.calledWith(
|
||||
'context.isServer has been deprecated, please use process.server instead.'
|
||||
)
|
||||
)
|
||||
t.true(
|
||||
warnSpy.calledWith(
|
||||
'context.isClient has been deprecated, please use process.client instead.'
|
||||
)
|
||||
)
|
||||
t.true(warnSpy.calledTwice)
|
||||
release()
|
||||
})
|
||||
|
||||
test.serial('Deprecated: dev in build.extend()', async t => {
|
||||
t.true(buildSpies.warn.withArgs('dev has been deprecated in build.extend(), please use isDev').calledTwice)
|
||||
t.true(
|
||||
buildSpies.warn.withArgs(
|
||||
'dev has been deprecated in build.extend(), please use isDev'
|
||||
).calledTwice
|
||||
)
|
||||
})
|
||||
|
||||
test.serial('Deprecated: nuxt.plugin()', async t => {
|
||||
|
@ -9,9 +9,12 @@ const readFile = promisify(fs.readFile)
|
||||
const rootDir = resolve(__dirname, 'fixtures/dll')
|
||||
const dllDir = resolve(rootDir, '.cache/client-dll')
|
||||
|
||||
const checkCache = (lib) => {
|
||||
return async (t) => {
|
||||
const manifest = await readFile(resolve(dllDir, `./${lib}-manifest.json`), 'utf-8')
|
||||
const checkCache = lib => {
|
||||
return async t => {
|
||||
const manifest = await readFile(
|
||||
resolve(dllDir, `./${lib}-manifest.json`),
|
||||
'utf-8'
|
||||
)
|
||||
t.truthy(JSON.parse(manifest).name)
|
||||
t.true(fs.existsSync(resolve(dllDir, `./${JSON.parse(manifest).name}.js`)))
|
||||
}
|
||||
|
@ -24,73 +24,94 @@ test.serial('Init Nuxt.js', async t => {
|
||||
})
|
||||
|
||||
test('Check .nuxt/router.js', t => {
|
||||
return readFile(resolve(__dirname, './fixtures/dynamic-routes/.nuxt/router.js'), 'utf-8')
|
||||
.then((routerFile) => {
|
||||
routerFile = routerFile
|
||||
.slice(routerFile.indexOf('routes: ['))
|
||||
.replace('routes: [', '[')
|
||||
.replace(/ _[0-9A-z]+,/g, ' "",')
|
||||
routerFile = routerFile.substr(routerFile.indexOf('['), routerFile.lastIndexOf(']') + 1)
|
||||
let routes = eval('( ' + routerFile + ')') // eslint-disable-line no-eval
|
||||
// pages/index.vue
|
||||
t.is(routes[0].path, '/')
|
||||
t.is(routes[0].name, 'index')
|
||||
// pages/test/index.vue
|
||||
t.is(routes[1].path, '/test')
|
||||
t.is(routes[1].name, 'test')
|
||||
// pages/posts.vue
|
||||
t.is(routes[2].path, '/posts')
|
||||
t.is(routes[2].name, 'posts')
|
||||
t.is(routes[2].children.length, 1)
|
||||
// pages/posts/_id.vue
|
||||
t.is(routes[2].children[0].path, ':id?')
|
||||
t.is(routes[2].children[0].name, 'posts-id')
|
||||
// pages/parent.vue
|
||||
t.is(routes[3].path, '/parent')
|
||||
t.falsy(routes[3].name) // parent route has no name
|
||||
// pages/parent/*.vue
|
||||
t.is(routes[3].children.length, 3) // parent has 3 children
|
||||
t.deepEqual(routes[3].children.map((r) => r.path), ['', 'teub', 'child'])
|
||||
t.deepEqual(routes[3].children.map((r) => r.name), ['parent', 'parent-teub', 'parent-child'])
|
||||
// pages/test/projects/index.vue
|
||||
t.is(routes[4].path, '/test/projects')
|
||||
t.is(routes[4].name, 'test-projects')
|
||||
// pages/test/users.vue
|
||||
t.is(routes[5].path, '/test/users')
|
||||
t.falsy(routes[5].name) // parent route has no name
|
||||
// pages/test/users/*.vue
|
||||
t.is(routes[5].children.length, 5) // parent has 5 children
|
||||
t.deepEqual(routes[5].children.map((r) => r.path), ['', 'projects', 'projects/:category', ':id', ':index/teub'])
|
||||
t.deepEqual(routes[5].children.map((r) => r.name), ['test-users', 'test-users-projects', 'test-users-projects-category', 'test-users-id', 'test-users-index-teub'])
|
||||
// pages/test/songs/toto.vue
|
||||
t.is(routes[6].path, '/test/songs/toto')
|
||||
t.is(routes[6].name, 'test-songs-toto')
|
||||
// pages/test/songs/_id.vue
|
||||
t.is(routes[7].path, '/test/songs/:id?')
|
||||
t.is(routes[7].name, 'test-songs-id')
|
||||
// pages/test/projects/_category.vue
|
||||
t.is(routes[8].path, '/test/projects/:category')
|
||||
t.is(routes[8].name, 'test-projects-category')
|
||||
// pages/users/_id.vue
|
||||
t.is(routes[9].path, '/users/:id?')
|
||||
t.is(routes[9].name, 'users-id')
|
||||
// pages/test/_.vue
|
||||
t.is(routes[10].path, '/test/*')
|
||||
t.is(routes[10].name, 'test-all')
|
||||
// pages/_slug.vue
|
||||
t.is(routes[11].path, '/:slug')
|
||||
t.is(routes[11].name, 'slug')
|
||||
// pages/_key/_id.vue
|
||||
t.is(routes[12].path, '/:key/:id?')
|
||||
t.is(routes[12].name, 'key-id')
|
||||
// pages/_.vue
|
||||
t.is(routes[13].path, '/*/p/*')
|
||||
t.is(routes[13].name, 'all-p-all')
|
||||
// pages/_/_.vue
|
||||
t.is(routes[14].path, '/*/*')
|
||||
t.is(routes[14].name, 'all-all')
|
||||
// pages/_.vue
|
||||
t.is(routes[15].path, '/*')
|
||||
t.is(routes[15].name, 'all')
|
||||
})
|
||||
return readFile(
|
||||
resolve(__dirname, './fixtures/dynamic-routes/.nuxt/router.js'),
|
||||
'utf-8'
|
||||
).then(routerFile => {
|
||||
routerFile = routerFile
|
||||
.slice(routerFile.indexOf('routes: ['))
|
||||
.replace('routes: [', '[')
|
||||
.replace(/ _[0-9A-z]+,/g, ' "",')
|
||||
routerFile = routerFile.substr(
|
||||
routerFile.indexOf('['),
|
||||
routerFile.lastIndexOf(']') + 1
|
||||
)
|
||||
let routes = eval('( ' + routerFile + ')') // eslint-disable-line no-eval
|
||||
// pages/index.vue
|
||||
t.is(routes[0].path, '/')
|
||||
t.is(routes[0].name, 'index')
|
||||
// pages/test/index.vue
|
||||
t.is(routes[1].path, '/test')
|
||||
t.is(routes[1].name, 'test')
|
||||
// pages/posts.vue
|
||||
t.is(routes[2].path, '/posts')
|
||||
t.is(routes[2].name, 'posts')
|
||||
t.is(routes[2].children.length, 1)
|
||||
// pages/posts/_id.vue
|
||||
t.is(routes[2].children[0].path, ':id?')
|
||||
t.is(routes[2].children[0].name, 'posts-id')
|
||||
// pages/parent.vue
|
||||
t.is(routes[3].path, '/parent')
|
||||
t.falsy(routes[3].name) // parent route has no name
|
||||
// pages/parent/*.vue
|
||||
t.is(routes[3].children.length, 3) // parent has 3 children
|
||||
t.deepEqual(routes[3].children.map(r => r.path), ['', 'teub', 'child'])
|
||||
t.deepEqual(routes[3].children.map(r => r.name), [
|
||||
'parent',
|
||||
'parent-teub',
|
||||
'parent-child'
|
||||
])
|
||||
// pages/test/projects/index.vue
|
||||
t.is(routes[4].path, '/test/projects')
|
||||
t.is(routes[4].name, 'test-projects')
|
||||
// pages/test/users.vue
|
||||
t.is(routes[5].path, '/test/users')
|
||||
t.falsy(routes[5].name) // parent route has no name
|
||||
// pages/test/users/*.vue
|
||||
t.is(routes[5].children.length, 5) // parent has 5 children
|
||||
t.deepEqual(routes[5].children.map(r => r.path), [
|
||||
'',
|
||||
'projects',
|
||||
'projects/:category',
|
||||
':id',
|
||||
':index/teub'
|
||||
])
|
||||
t.deepEqual(routes[5].children.map(r => r.name), [
|
||||
'test-users',
|
||||
'test-users-projects',
|
||||
'test-users-projects-category',
|
||||
'test-users-id',
|
||||
'test-users-index-teub'
|
||||
])
|
||||
// pages/test/songs/toto.vue
|
||||
t.is(routes[6].path, '/test/songs/toto')
|
||||
t.is(routes[6].name, 'test-songs-toto')
|
||||
// pages/test/songs/_id.vue
|
||||
t.is(routes[7].path, '/test/songs/:id?')
|
||||
t.is(routes[7].name, 'test-songs-id')
|
||||
// pages/test/projects/_category.vue
|
||||
t.is(routes[8].path, '/test/projects/:category')
|
||||
t.is(routes[8].name, 'test-projects-category')
|
||||
// pages/users/_id.vue
|
||||
t.is(routes[9].path, '/users/:id?')
|
||||
t.is(routes[9].name, 'users-id')
|
||||
// pages/test/_.vue
|
||||
t.is(routes[10].path, '/test/*')
|
||||
t.is(routes[10].name, 'test-all')
|
||||
// pages/_slug.vue
|
||||
t.is(routes[11].path, '/:slug')
|
||||
t.is(routes[11].name, 'slug')
|
||||
// pages/_key/_id.vue
|
||||
t.is(routes[12].path, '/:key/:id?')
|
||||
t.is(routes[12].name, 'key-id')
|
||||
// pages/_.vue
|
||||
t.is(routes[13].path, '/*/p/*')
|
||||
t.is(routes[13].name, 'all-p-all')
|
||||
// pages/_/_.vue
|
||||
t.is(routes[14].path, '/*/*')
|
||||
t.is(routes[14].name, 'all-all')
|
||||
// pages/_.vue
|
||||
t.is(routes[15].path, '/*')
|
||||
t.is(routes[15].name, 'all')
|
||||
})
|
||||
})
|
||||
|
@ -5,7 +5,7 @@ import { Nuxt, Builder } from '..'
|
||||
import { interceptLog, interceptError, release } from './helpers/console'
|
||||
|
||||
const port = 4005
|
||||
const url = (route) => 'http://localhost:' + port + route
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt = null
|
||||
|
||||
@ -46,13 +46,19 @@ test.serial('/ with renderAndGetWindow()', async t => {
|
||||
t.is(err.response.statusMessage, 'NuxtServerError')
|
||||
release()
|
||||
t.true(errorSpy.calledOnce)
|
||||
t.true(errorSpy.getCall(0).args[0].message.includes('render function or template not defined in component: anonymous'))
|
||||
t.true(
|
||||
errorSpy
|
||||
.getCall(0)
|
||||
.args[0].message.includes(
|
||||
'render function or template not defined in component: anonymous'
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
test.serial('/ with text/json content', async t => {
|
||||
const opts = {
|
||||
headers: {
|
||||
'accept': 'application/json'
|
||||
accept: 'application/json'
|
||||
},
|
||||
resolveWithFullResponse: true
|
||||
}
|
||||
@ -61,7 +67,13 @@ test.serial('/ with text/json content', async t => {
|
||||
t.is(headers['content-type'], 'text/json; charset=utf-8')
|
||||
release()
|
||||
t.true(errorSpy.calledOnce)
|
||||
t.true(errorSpy.getCall(0).args[0].message.includes('render function or template not defined in component: anonymous'))
|
||||
t.true(
|
||||
errorSpy
|
||||
.getCall(0)
|
||||
.args[0].message.includes(
|
||||
'render function or template not defined in component: anonymous'
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
// Close server and ask nuxt to stop listening to file changes
|
||||
|
@ -6,7 +6,7 @@ import rp from 'request-promise-native'
|
||||
import { interceptLog } from './helpers/console'
|
||||
|
||||
const port = 4000
|
||||
const url = (route) => 'http://localhost:' + port + route
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt
|
||||
let app
|
||||
|
4
test/fixtures/basic/nuxt.config.js
vendored
4
test/fixtures/basic/nuxt.config.js
vendored
@ -21,8 +21,6 @@ module.exports = {
|
||||
transition: false,
|
||||
build: {
|
||||
scopeHoisting: true,
|
||||
postcss: [
|
||||
require('postcss-cssnext')()
|
||||
]
|
||||
postcss: [require('postcss-cssnext')()]
|
||||
}
|
||||
}
|
||||
|
4
test/fixtures/deprecate/nuxt.config.js
vendored
4
test/fixtures/deprecate/nuxt.config.js
vendored
@ -1,7 +1,5 @@
|
||||
module.exports = {
|
||||
modules: [
|
||||
'~/modules/hooks'
|
||||
],
|
||||
modules: ['~/modules/hooks'],
|
||||
build: {
|
||||
stats: false,
|
||||
extend(config, options) {
|
||||
|
4
test/fixtures/dll/nuxt.config.js
vendored
4
test/fixtures/dll/nuxt.config.js
vendored
@ -4,7 +4,9 @@ module.exports = {
|
||||
dll: true,
|
||||
extend(config, options) {
|
||||
if (options.isClient) {
|
||||
const dlls = config.plugins.filter(plugin => plugin.constructor.name === 'DllReferencePlugin')
|
||||
const dlls = config.plugins.filter(
|
||||
plugin => plugin.constructor.name === 'DllReferencePlugin'
|
||||
)
|
||||
console.log('Using dll for ' + dlls.length + ' libs') // eslint-disable-line no-console
|
||||
}
|
||||
return config
|
||||
|
8
test/fixtures/module/nuxt.config.js
vendored
8
test/fixtures/module/nuxt.config.js
vendored
@ -9,11 +9,9 @@ module.exports = {
|
||||
foo: 'bar'
|
||||
}
|
||||
},
|
||||
['./modules/template', {baz: 'ping'}]
|
||||
],
|
||||
serverMiddleware: [
|
||||
'./modules/middleware/midd2'
|
||||
['./modules/template', { baz: 'ping' }]
|
||||
],
|
||||
serverMiddleware: ['./modules/middleware/midd2'],
|
||||
hooks(hook) {
|
||||
hook('ready', nuxt => {
|
||||
nuxt.__ready_called__ = true
|
||||
@ -22,7 +20,7 @@ module.exports = {
|
||||
builder.__build_done__ = true
|
||||
})
|
||||
// Add hook for renderer
|
||||
hook('render:before', (renderer) => {
|
||||
hook('render:before', renderer => {
|
||||
renderer.useMiddleware({
|
||||
path: '/use-middleware',
|
||||
handler: '~/modules/middleware/use-middleware'
|
||||
|
8
test/fixtures/with-config/nuxt.config.js
vendored
8
test/fixtures/with-config/nuxt.config.js
vendored
@ -16,9 +16,7 @@ module.exports = {
|
||||
]
|
||||
}
|
||||
},
|
||||
modulesDir: [
|
||||
path.join(__dirname, '..', '..', '..', 'node_modules')
|
||||
],
|
||||
modulesDir: [path.join(__dirname, '..', '..', '..', 'node_modules')],
|
||||
transition: 'test',
|
||||
layoutTransition: 'test',
|
||||
loadingIndicator: 'circle',
|
||||
@ -63,9 +61,7 @@ module.exports = {
|
||||
})
|
||||
}
|
||||
},
|
||||
css: [
|
||||
{ src: '~/assets/app.css' }
|
||||
],
|
||||
css: [{ src: '~/assets/app.css' }],
|
||||
render: {
|
||||
http2: {
|
||||
push: true,
|
||||
|
5
test/fixtures/with-config/postcss.config.js
vendored
5
test/fixtures/with-config/postcss.config.js
vendored
@ -6,10 +6,7 @@ module.exports = {
|
||||
plugins: {
|
||||
'postcss-import': {
|
||||
root: rootDir,
|
||||
path: [
|
||||
rootDir,
|
||||
modulesDir
|
||||
]
|
||||
path: [rootDir, modulesDir]
|
||||
},
|
||||
'postcss-url': {},
|
||||
'postcss-cssnext': {}
|
||||
|
@ -60,7 +60,7 @@ test('initRoutes with routes (fn(cb, args))', async t => {
|
||||
const config = {
|
||||
generate: {
|
||||
routes(cb, arg1, arg2, arg3, arg4) {
|
||||
cb(null, [ arg1, arg2, arg3, arg4 ])
|
||||
cb(null, [arg1, arg2, arg3, arg4])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,9 +4,14 @@ let browser = null
|
||||
|
||||
export async function start(options = {}) {
|
||||
// https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions
|
||||
browser = await puppeteer.launch(Object.assign({
|
||||
args: ['--no-sandbox', '--disable-setuid-sandbox']
|
||||
}, options))
|
||||
browser = await puppeteer.launch(
|
||||
Object.assign(
|
||||
{
|
||||
args: ['--no-sandbox', '--disable-setuid-sandbox']
|
||||
},
|
||||
options
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
export async function stop() {
|
||||
@ -19,25 +24,38 @@ export async function page(url) {
|
||||
const page = await browser.newPage()
|
||||
await page.goto(url)
|
||||
await page.waitForFunction('!!window.$nuxt')
|
||||
page.html = () => page.evaluate(() => window.document.documentElement.outerHTML)
|
||||
page.$text = (selector) => page.$eval(selector, (el) => el.textContent)
|
||||
page.$$text = (selector) => page.$$eval(selector, (els) => els.map((el) => el.textContent))
|
||||
page.$attr = (selector, attr) => page.$eval(selector, (el, attr) => el.getAttribute(attr), attr)
|
||||
page.$$attr = (selector, attr) => page.$$eval(selector, (els, attr) => els.map((el) => el.getAttribute(attr)), attr)
|
||||
page.html = () =>
|
||||
page.evaluate(() => window.document.documentElement.outerHTML)
|
||||
page.$text = selector => page.$eval(selector, el => el.textContent)
|
||||
page.$$text = selector =>
|
||||
page.$$eval(selector, els => els.map(el => el.textContent))
|
||||
page.$attr = (selector, attr) =>
|
||||
page.$eval(selector, (el, attr) => el.getAttribute(attr), attr)
|
||||
page.$$attr = (selector, attr) =>
|
||||
page.$$eval(
|
||||
selector,
|
||||
(els, attr) => els.map(el => el.getAttribute(attr)),
|
||||
attr
|
||||
)
|
||||
page.$nuxt = await page.evaluateHandle('window.$nuxt')
|
||||
|
||||
page.nuxt = {
|
||||
async navigate(path, waitEnd = true) {
|
||||
const hook = page.evaluate(() => {
|
||||
return new Promise((resolve) => window.$nuxt.$once('routeChanged', resolve))
|
||||
.then(() => new Promise((resolve) => setTimeout(resolve, 50)))
|
||||
return new Promise(resolve =>
|
||||
window.$nuxt.$once('routeChanged', resolve)
|
||||
).then(() => new Promise(resolve => setTimeout(resolve, 50)))
|
||||
})
|
||||
await page.evaluate(($nuxt, path) => $nuxt.$router.push(path), page.$nuxt, path)
|
||||
await page.evaluate(
|
||||
($nuxt, path) => $nuxt.$router.push(path),
|
||||
page.$nuxt,
|
||||
path
|
||||
)
|
||||
if (waitEnd) await hook
|
||||
return { hook }
|
||||
},
|
||||
routeData() {
|
||||
return page.evaluate(($nuxt) => {
|
||||
return page.evaluate($nuxt => {
|
||||
return {
|
||||
path: $nuxt.$route.path,
|
||||
query: $nuxt.$route.query
|
||||
@ -45,13 +63,13 @@ export async function page(url) {
|
||||
}, page.$nuxt)
|
||||
},
|
||||
loadingData() {
|
||||
return page.evaluate(($nuxt) => $nuxt.$loading.$data, page.$nuxt)
|
||||
return page.evaluate($nuxt => $nuxt.$loading.$data, page.$nuxt)
|
||||
},
|
||||
errorData() {
|
||||
return page.evaluate(($nuxt) => $nuxt.nuxt.err, page.$nuxt)
|
||||
return page.evaluate($nuxt => $nuxt.nuxt.err, page.$nuxt)
|
||||
},
|
||||
storeState() {
|
||||
return page.evaluate(($nuxt) => $nuxt.$store.state, page.$nuxt)
|
||||
return page.evaluate($nuxt => $nuxt.$store.state, page.$nuxt)
|
||||
}
|
||||
}
|
||||
return page
|
||||
|
@ -4,7 +4,9 @@ let context = null
|
||||
|
||||
export function release() {
|
||||
if (context === null) {
|
||||
process.stderr.write('Console spy context was empty, did a previous test already release it?\n')
|
||||
process.stderr.write(
|
||||
'Console spy context was empty, did a previous test already release it?\n'
|
||||
)
|
||||
return
|
||||
}
|
||||
|
||||
@ -32,7 +34,9 @@ export function release() {
|
||||
|
||||
export async function intercept(levels, msg, cb) {
|
||||
if (context !== null) {
|
||||
process.stderr.write('Console spy context was not empty, did a previous test not release it?\n')
|
||||
process.stderr.write(
|
||||
'Console spy context was not empty, did a previous test not release it?\n'
|
||||
)
|
||||
}
|
||||
context = {}
|
||||
|
||||
|
@ -25,7 +25,9 @@ test('Fail to build when no pages/ directory but is in the parent', t => {
|
||||
return new Builder(nuxt).build().catch(err => {
|
||||
let s = String(err)
|
||||
t.true(s.includes('No `pages` directory found'))
|
||||
t.true(s.includes('Did you mean to run `nuxt` in the parent (`../`) directory?'))
|
||||
t.true(
|
||||
s.includes('Did you mean to run `nuxt` in the parent (`../`) directory?')
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
@ -36,7 +38,7 @@ test('Fail to build when no pages/ directory', t => {
|
||||
})
|
||||
return new Builder(nuxt).build().catch(err => {
|
||||
let s = String(err)
|
||||
t.true(s.includes('Couldn\'t find a `pages` directory'))
|
||||
t.true(s.includes("Couldn't find a `pages` directory"))
|
||||
t.true(s.includes('Please create one under the project root'))
|
||||
})
|
||||
})
|
||||
|
@ -5,7 +5,7 @@ import { Nuxt, Builder } from '..'
|
||||
import { intercept } from './helpers/console'
|
||||
|
||||
const port = 4006
|
||||
const url = (route) => 'http://localhost:' + port + route
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt = null
|
||||
let builder = null
|
||||
@ -30,12 +30,19 @@ test.serial('Init Nuxt.js', async t => {
|
||||
})
|
||||
|
||||
test.serial('Vendor', async t => {
|
||||
t.true(nuxt.options.build.vendor.indexOf('lodash') !== -1, 'lodash added to config')
|
||||
t.true(
|
||||
nuxt.options.build.vendor.indexOf('lodash') !== -1,
|
||||
'lodash added to config'
|
||||
)
|
||||
})
|
||||
|
||||
test.serial('Plugin', async t => {
|
||||
t.true(normalize(nuxt.options.plugins[0].src)
|
||||
.includes(normalize('fixtures/module/.nuxt/basic.reverse.')), 'plugin added to config')
|
||||
t.true(
|
||||
normalize(nuxt.options.plugins[0].src).includes(
|
||||
normalize('fixtures/module/.nuxt/basic.reverse.')
|
||||
),
|
||||
'plugin added to config'
|
||||
)
|
||||
const { html } = await nuxt.renderRoute('/')
|
||||
t.true(html.includes('<h1>TXUN</h1>'), 'plugin works')
|
||||
})
|
||||
|
@ -6,7 +6,7 @@ import { interceptLog, release } from './helpers/console'
|
||||
let nuxt = null
|
||||
|
||||
const port = 4012
|
||||
const url = (route) => 'http://localhost:' + port + route
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
const renderRoute = async _url => {
|
||||
const window = await nuxt.renderAndGetWindow(url(_url))
|
||||
@ -73,7 +73,9 @@ test.serial('/mounted', async t => {
|
||||
})
|
||||
|
||||
test('/_nuxt/ (access publicPath in spa mode)', async t => {
|
||||
const { response: { statusCode, statusMessage } } = await t.throws(renderRoute('/_nuxt/'))
|
||||
const { response: { statusCode, statusMessage } } = await t.throws(
|
||||
renderRoute('/_nuxt/')
|
||||
)
|
||||
t.is(statusCode, 404)
|
||||
t.is(statusMessage, 'ResourceNotFound')
|
||||
})
|
||||
|
@ -13,7 +13,7 @@ const range = n => [...Array(n).keys()]
|
||||
const FOOBAR_REGEX = /<foobar>([\s\S]*)<\/foobar>/
|
||||
const match = (regex, text) => (regex.exec(text) || [])[1]
|
||||
|
||||
const url = (route) => 'http://localhost:' + port + route
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
const isWindows = /^win/.test(process.platform)
|
||||
|
||||
@ -93,7 +93,7 @@ test('unique responses with fetch', async t => {
|
||||
// Making 16K requests by default
|
||||
// Related issue: https://github.com/nuxt/nuxt.js/issues/1354
|
||||
const stressTest = async (t, _url, concurrency = 64, steps = 256) => {
|
||||
let statusCodes = { }
|
||||
let statusCodes = {}
|
||||
|
||||
// appveyor memory limit!
|
||||
if (isWindows) {
|
||||
|
@ -21,7 +21,7 @@ test('setAnsiColors', t => {
|
||||
t.pass()
|
||||
})
|
||||
|
||||
test('waitFor', async (t) => {
|
||||
test('waitFor', async t => {
|
||||
let s = Date.now()
|
||||
await Utils.waitFor(100)
|
||||
t.true(Date.now() - s >= 100)
|
||||
@ -36,10 +36,9 @@ test('promisifyRoute (array)', t => {
|
||||
const array = [1]
|
||||
const promise = Utils.promisifyRoute(array)
|
||||
t.is(typeof promise, 'object')
|
||||
return promise
|
||||
.then((res) => {
|
||||
t.is(res, array)
|
||||
})
|
||||
return promise.then(res => {
|
||||
t.is(res, array)
|
||||
})
|
||||
})
|
||||
|
||||
test('promisifyRoute (fn => array)', t => {
|
||||
@ -49,40 +48,37 @@ test('promisifyRoute (fn => array)', t => {
|
||||
}
|
||||
const promise = Utils.promisifyRoute(fn)
|
||||
t.is(typeof promise, 'object')
|
||||
return promise
|
||||
.then((res) => {
|
||||
t.is(res, array)
|
||||
})
|
||||
return promise.then(res => {
|
||||
t.is(res, array)
|
||||
})
|
||||
})
|
||||
|
||||
test('promisifyRoute (fn => promise)', t => {
|
||||
const array = [1, 2, 3]
|
||||
const fn = function () {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise(resolve => {
|
||||
resolve(array)
|
||||
})
|
||||
}
|
||||
const promise = Utils.promisifyRoute(fn)
|
||||
t.is(typeof promise, 'object')
|
||||
return promise
|
||||
.then((res) => {
|
||||
t.is(res, array)
|
||||
})
|
||||
return promise.then(res => {
|
||||
t.is(res, array)
|
||||
})
|
||||
})
|
||||
|
||||
test('promisifyRoute ((fn(args) => promise))', t => {
|
||||
const fn = function (array) {
|
||||
return new Promise((resolve) => {
|
||||
return new Promise(resolve => {
|
||||
resolve(array)
|
||||
})
|
||||
}
|
||||
const array = [1, 2, 3]
|
||||
const promise = Utils.promisifyRoute(fn, array)
|
||||
t.is(typeof promise, 'object')
|
||||
return promise
|
||||
.then((res) => {
|
||||
t.is(res, array)
|
||||
})
|
||||
return promise.then(res => {
|
||||
t.is(res, array)
|
||||
})
|
||||
})
|
||||
|
||||
test('promisifyRoute (fn(cb) with error)', t => {
|
||||
@ -91,10 +87,9 @@ test('promisifyRoute (fn(cb) with error)', t => {
|
||||
}
|
||||
const promise = Utils.promisifyRoute(fn)
|
||||
t.is(typeof promise, 'object')
|
||||
return promise
|
||||
.catch((e) => {
|
||||
t.is(e.message, 'Error here')
|
||||
})
|
||||
return promise.catch(e => {
|
||||
t.is(e.message, 'Error here')
|
||||
})
|
||||
})
|
||||
|
||||
test('promisifyRoute (fn(cb, args) with error)', t => {
|
||||
@ -104,10 +99,9 @@ test('promisifyRoute (fn(cb, args) with error)', t => {
|
||||
const array = [1, 2, 3, 4]
|
||||
const promise = Utils.promisifyRoute(fn, array)
|
||||
t.is(typeof promise, 'object')
|
||||
return promise
|
||||
.catch((e) => {
|
||||
t.is(e.message, 'Error here: ' + array.join())
|
||||
})
|
||||
return promise.catch(e => {
|
||||
t.is(e.message, 'Error here: ' + array.join())
|
||||
})
|
||||
})
|
||||
|
||||
test('promisifyRoute (fn(cb) with result)', t => {
|
||||
@ -117,10 +111,9 @@ test('promisifyRoute (fn(cb) with result)', t => {
|
||||
}
|
||||
const promise = Utils.promisifyRoute(fn)
|
||||
t.is(typeof promise, 'object')
|
||||
return promise
|
||||
.then((res) => {
|
||||
t.is(res, array)
|
||||
})
|
||||
return promise.then(res => {
|
||||
t.is(res, array)
|
||||
})
|
||||
})
|
||||
|
||||
test('promisifyRoute (fn(cb, args) with result)', t => {
|
||||
@ -131,11 +124,10 @@ test('promisifyRoute (fn(cb, args) with result)', t => {
|
||||
const object = { a: 1 }
|
||||
const promise = Utils.promisifyRoute(fn, array, object)
|
||||
t.is(typeof promise, 'object')
|
||||
return promise
|
||||
.then((res) => {
|
||||
t.is(res.array, array)
|
||||
t.is(res.object, object)
|
||||
})
|
||||
return promise.then(res => {
|
||||
t.is(res.array, array)
|
||||
t.is(res.object, object)
|
||||
})
|
||||
})
|
||||
|
||||
test('chainFn (mutate, mutate)', t => {
|
||||
|
@ -6,7 +6,7 @@ import styleLoader from '../lib/builder/webpack/style-loader'
|
||||
import { interceptLog, release } from './helpers/console'
|
||||
|
||||
const port = 4007
|
||||
const url = (route) => 'http://localhost:' + port + route
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt = null
|
||||
let builder = null
|
||||
@ -45,7 +45,11 @@ test('/ (global styles inlined)', async t => {
|
||||
|
||||
test('/ (preload fonts)', async t => {
|
||||
const { html } = await nuxt.renderRoute('/')
|
||||
t.true(html.includes('<link rel="preload" href="/test/orion/fonts/roboto.7cf5d7c.woff2" as="font" type="font/woff2" crossorigin'))
|
||||
t.true(
|
||||
html.includes(
|
||||
'<link rel="preload" href="/test/orion/fonts/roboto.7cf5d7c.woff2" as="font" type="font/woff2" crossorigin'
|
||||
)
|
||||
)
|
||||
})
|
||||
|
||||
test('/ (custom app.html)', async t => {
|
||||
@ -168,12 +172,17 @@ test.serial('/test/about-bis (added with extendRoutes)', async t => {
|
||||
})
|
||||
|
||||
test('Check stats.json generated by build.analyze', t => {
|
||||
const stats = require(resolve(__dirname, 'fixtures/with-config/.nuxt/dist/stats.json'))
|
||||
const stats = require(resolve(
|
||||
__dirname,
|
||||
'fixtures/with-config/.nuxt/dist/stats.json'
|
||||
))
|
||||
t.is(stats.assets.length, 35)
|
||||
})
|
||||
|
||||
test('Check /test/test.txt with custom serve-static options', async t => {
|
||||
const { headers } = await rp(url('/test/test.txt'), { resolveWithFullResponse: true })
|
||||
const { headers } = await rp(url('/test/test.txt'), {
|
||||
resolveWithFullResponse: true
|
||||
})
|
||||
t.is(headers['cache-control'], 'public, max-age=31536000')
|
||||
})
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user