style: format with prettier

This commit is contained in:
Pooya Parsa 2018-01-13 08:52:11 +03:30
parent b3e9952976
commit 10d1b5974c
41 changed files with 958 additions and 541 deletions

View File

@ -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'
)
}
}

View File

@ -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,

View File

@ -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

View File

@ -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

View File

@ -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,

View File

@ -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)
}

View File

@ -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

View File

@ -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.'
}
}

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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'
)

View File

@ -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()
)

View File

@ -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`
)

View File

@ -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 => {

View File

@ -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

View File

@ -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)

View File

@ -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 => {

View File

@ -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">&lt;p&gt;Loading...&lt;/p&gt;</div>'))
t.true(
html.includes(
'<div class="no-ssr-placeholder">&lt;p&gt;Loading...&lt;/p&gt;</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'))
})

View File

@ -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

View File

@ -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
}

View File

@ -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 => {

View File

@ -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`)))
}

View File

@ -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')
})
})

View File

@ -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

View File

@ -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

View File

@ -21,8 +21,6 @@ module.exports = {
transition: false,
build: {
scopeHoisting: true,
postcss: [
require('postcss-cssnext')()
]
postcss: [require('postcss-cssnext')()]
}
}

View File

@ -1,7 +1,5 @@
module.exports = {
modules: [
'~/modules/hooks'
],
modules: ['~/modules/hooks'],
build: {
stats: false,
extend(config, options) {

View File

@ -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

View File

@ -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'

View File

@ -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,

View File

@ -6,10 +6,7 @@ module.exports = {
plugins: {
'postcss-import': {
root: rootDir,
path: [
rootDir,
modulesDir
]
path: [rootDir, modulesDir]
},
'postcss-url': {},
'postcss-cssnext': {}

View File

@ -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])
}
}
}

View File

@ -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

View File

@ -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 = {}

View File

@ -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'))
})
})

View File

@ -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')
})

View File

@ -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')
})

View File

@ -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) {

View File

@ -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 => {

View File

@ -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')
})