mirror of
https://github.com/nuxt/nuxt.git
synced 2025-01-30 23:32:38 +00:00
Merge branch 'dev' of github.com:nuxt/nuxt.js into dev
This commit is contained in:
commit
3a2b732965
@ -6,9 +6,9 @@ node_js:
|
|||||||
before_install:
|
before_install:
|
||||||
- if [[ `npm -v` != 3* ]]; then npm i -g npm@3; fi
|
- if [[ `npm -v` != 3* ]]; then npm i -g npm@3; fi
|
||||||
install:
|
install:
|
||||||
- npm install
|
- yarn install
|
||||||
- npm run build
|
- yarn run build
|
||||||
script:
|
script:
|
||||||
- npm test
|
- yarn run test
|
||||||
after_success:
|
after_success:
|
||||||
- npm run coverage
|
- yarn run coverage
|
||||||
|
@ -7,15 +7,16 @@ install:
|
|||||||
# Get the latest stable version of Node.js or io.js
|
# Get the latest stable version of Node.js or io.js
|
||||||
- ps: Install-Product node $env:nodejs_version
|
- ps: Install-Product node $env:nodejs_version
|
||||||
# install modules
|
# install modules
|
||||||
- npm install
|
- yarn install
|
||||||
|
|
||||||
# Post-install test scripts.
|
# Post-install test scripts.
|
||||||
test_script:
|
test_script:
|
||||||
# Output useful info for debugging.
|
# Output useful info for debugging.
|
||||||
- node --version
|
- node --version
|
||||||
- npm --version
|
- npm --version
|
||||||
|
- yarn --version
|
||||||
# run tests
|
# run tests
|
||||||
- npm test
|
- yarn run test
|
||||||
|
|
||||||
# Don't actually build.
|
# Don't actually build.
|
||||||
build: off
|
build: off
|
||||||
|
@ -1,16 +1,13 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
|
loading: { color: 'cyan' },
|
||||||
build: {
|
build: {
|
||||||
vendor: ['vue-i18n']
|
vendor: ['vue-i18n']
|
||||||
},
|
},
|
||||||
router: {
|
router: {
|
||||||
middleware: 'i18n'
|
middleware: 'i18n'
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: ['~plugins/i18n.js',],
|
||||||
// Will inject the plugin in the $root app and also in the context as `i18n`
|
|
||||||
{ src: '~plugins/i18n.js', injectAs: 'i18n' }
|
|
||||||
],
|
|
||||||
generate: {
|
generate: {
|
||||||
routes: ['/', '/about', '/fr', '/fr/about']
|
routes: ['/', '/about', '/fr', '/fr/about']
|
||||||
},
|
}
|
||||||
loading: { color: 'cyan' },
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
{
|
{
|
||||||
"name": "nuxt-i18n",
|
"name": "nuxt-i18n",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"nuxt": "latest",
|
"nuxt": "1.0.0-alpha.3",
|
||||||
"vue-i18n": "^7.0.0"
|
"vue-i18n": "^7.0.0"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
@ -19,6 +19,7 @@ const isDev = <%= isDev %>
|
|||||||
export default async (context) => {
|
export default async (context) => {
|
||||||
const { app, router<%= (store ? ', store' : '') %> } = await createApp(context)
|
const { app, router<%= (store ? ', store' : '') %> } = await createApp(context)
|
||||||
const _app = new Vue(app)
|
const _app = new Vue(app)
|
||||||
|
const _noopApp = new Vue({ render: (h) => h('div') })
|
||||||
// Add store to the context
|
// Add store to the context
|
||||||
<%= (store ? 'context.store = store' : '') %>
|
<%= (store ? 'context.store = store' : '') %>
|
||||||
// Add route to the context
|
// Add route to the context
|
||||||
@ -84,7 +85,7 @@ export default async (context) => {
|
|||||||
if (!context.nuxt.error) {
|
if (!context.nuxt.error) {
|
||||||
await middlewareSeries(midd, ctx)
|
await middlewareSeries(midd, ctx)
|
||||||
}
|
}
|
||||||
if (context.redirected) return _app
|
if (context.redirected) return _noopApp
|
||||||
// Set layout
|
// Set layout
|
||||||
let layout = Components.length ? Components[0].options.layout : NuxtError.layout
|
let layout = Components.length ? Components[0].options.layout : NuxtError.layout
|
||||||
if (typeof layout === 'function') layout = layout(ctx)
|
if (typeof layout === 'function') layout = layout(ctx)
|
||||||
@ -109,7 +110,7 @@ export default async (context) => {
|
|||||||
if (!context.nuxt.error) {
|
if (!context.nuxt.error) {
|
||||||
await middlewareSeries(midd, ctx)
|
await middlewareSeries(midd, ctx)
|
||||||
}
|
}
|
||||||
if (context.redirected) return _app
|
if (context.redirected) return _noopApp
|
||||||
// Call .validate()
|
// Call .validate()
|
||||||
let isValid = true
|
let isValid = true
|
||||||
Components.forEach((Component) => {
|
Components.forEach((Component) => {
|
||||||
|
33
lib/build.js
33
lib/build.js
@ -76,23 +76,24 @@ export function options () {
|
|||||||
if (this.dev && isUrl(this.options.build.publicPath)) {
|
if (this.dev && isUrl(this.options.build.publicPath)) {
|
||||||
this.options.build.publicPath = defaults.publicPath
|
this.options.build.publicPath = defaults.publicPath
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function production () {
|
||||||
// Production, create server-renderer
|
// Production, create server-renderer
|
||||||
if (!this.dev) {
|
webpackStats = {
|
||||||
webpackStats = {
|
chunks: false,
|
||||||
chunks: false,
|
children: false,
|
||||||
children: false,
|
modules: false,
|
||||||
modules: false,
|
colors: true
|
||||||
colors: true
|
}
|
||||||
}
|
const serverConfig = getWebpackServerConfig.call(this)
|
||||||
const serverConfig = getWebpackServerConfig.call(this)
|
const bundlePath = join(serverConfig.output.path, 'server-bundle.json')
|
||||||
const bundlePath = join(serverConfig.output.path, 'server-bundle.json')
|
const manifestPath = join(serverConfig.output.path, 'client-manifest.json')
|
||||||
const manifestPath = join(serverConfig.output.path, 'client-manifest.json')
|
if (fs.existsSync(bundlePath) && fs.existsSync(manifestPath)) {
|
||||||
if (fs.existsSync(bundlePath) && fs.existsSync(manifestPath)) {
|
const bundle = fs.readFileSync(bundlePath, 'utf8')
|
||||||
const bundle = fs.readFileSync(bundlePath, 'utf8')
|
const manifest = fs.readFileSync(manifestPath, 'utf8')
|
||||||
const manifest = fs.readFileSync(manifestPath, 'utf8')
|
createRenderer.call(this, JSON.parse(bundle), JSON.parse(manifest))
|
||||||
createRenderer.call(this, JSON.parse(bundle), JSON.parse(manifest))
|
addAppTemplate.call(this)
|
||||||
addAppTemplate.call(this)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +42,10 @@ export default async function () {
|
|||||||
const s = Date.now()
|
const s = Date.now()
|
||||||
let errors = []
|
let errors = []
|
||||||
/*
|
/*
|
||||||
|
** Wait for modules to be initialized
|
||||||
|
*/
|
||||||
|
await this.ready()
|
||||||
|
/*
|
||||||
** Set variables
|
** Set variables
|
||||||
*/
|
*/
|
||||||
this.options.generate = _.defaultsDeep(this.options.generate, defaults)
|
this.options.generate = _.defaultsDeep(this.options.generate, defaults)
|
||||||
|
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
import path from 'path'
|
import path from 'path'
|
||||||
import fs from 'fs'
|
import fs from 'fs'
|
||||||
import {uniq} from 'lodash'
|
import { uniq } from 'lodash'
|
||||||
import hash from 'hash-sum'
|
import hash from 'hash-sum'
|
||||||
import {chainFn, sequence} from './utils'
|
import { chainFn, sequence } from './utils'
|
||||||
|
|
||||||
const debug = require('debug')('nuxt:module')
|
const debug = require('debug')('nuxt:module')
|
||||||
|
|
||||||
@ -12,17 +12,18 @@ class Module {
|
|||||||
constructor (nuxt) {
|
constructor (nuxt) {
|
||||||
this.nuxt = nuxt
|
this.nuxt = nuxt
|
||||||
this.options = nuxt.options
|
this.options = nuxt.options
|
||||||
this.modules = []
|
this.requiredModules = []
|
||||||
this.initing = this.ready()
|
this.initing = this.ready()
|
||||||
}
|
}
|
||||||
|
|
||||||
async ready () {
|
async ready () {
|
||||||
if (this.initing) {
|
if (this.initing) {
|
||||||
await this.initing
|
await this.initing
|
||||||
return
|
return this
|
||||||
}
|
}
|
||||||
// Install all modules in sequence
|
// Install all modules in sequence
|
||||||
await sequence(this.options.modules, this.addModule.bind(this))
|
await sequence(this.options.modules, this.addModule.bind(this))
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
addVendor (vendor) {
|
addVendor (vendor) {
|
||||||
@ -81,14 +82,11 @@ class Module {
|
|||||||
}
|
}
|
||||||
|
|
||||||
requireModule (moduleOpts) {
|
requireModule (moduleOpts) {
|
||||||
if (this.modules.indexOf(moduleOpts) !== -1 || this.modules.indexOf(moduleOpts.src) !== -1) {
|
// Require once
|
||||||
return false
|
return this.addModule(moduleOpts, true)
|
||||||
}
|
|
||||||
this.modules.push(moduleOpts.src || moduleOpts)
|
|
||||||
return this.addModule(moduleOpts)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
addModule (moduleOpts) {
|
addModule (moduleOpts, requireOnce) {
|
||||||
/* istanbul ignore if */
|
/* istanbul ignore if */
|
||||||
if (!moduleOpts) {
|
if (!moduleOpts) {
|
||||||
return
|
return
|
||||||
@ -128,6 +126,19 @@ class Module {
|
|||||||
console.error(`[nuxt] Module [${originalSrc}] should export a function`)
|
console.error(`[nuxt] Module [${originalSrc}] should export a function`)
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
}
|
}
|
||||||
|
// Module meta
|
||||||
|
if (!module.meta) {
|
||||||
|
module.meta = {}
|
||||||
|
}
|
||||||
|
if (module.meta.name) {
|
||||||
|
const alreadyRequired = this.requiredModules.indexOf(module.meta.name) !== -1
|
||||||
|
if (requireOnce && alreadyRequired) {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
if (!alreadyRequired) {
|
||||||
|
this.requiredModules.push(module.meta.name)
|
||||||
|
}
|
||||||
|
}
|
||||||
// Call module with `this` context and pass options
|
// Call module with `this` context and pass options
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
const result = module.call(this, options, err => {
|
const result = module.call(this, options, err => {
|
||||||
|
26
lib/nuxt.js
26
lib/nuxt.js
@ -51,6 +51,9 @@ class Nuxt {
|
|||||||
scrollBehavior: null
|
scrollBehavior: null
|
||||||
},
|
},
|
||||||
render: {
|
render: {
|
||||||
|
http2: {
|
||||||
|
push: false
|
||||||
|
},
|
||||||
static: {},
|
static: {},
|
||||||
gzip: {
|
gzip: {
|
||||||
threshold: 0
|
threshold: 0
|
||||||
@ -66,11 +69,11 @@ class Nuxt {
|
|||||||
}
|
}
|
||||||
// Sanitization
|
// Sanitization
|
||||||
if (options.loading === true) delete options.loading
|
if (options.loading === true) delete options.loading
|
||||||
if (options.router && typeof options.router.middleware === 'string') options.router.middleware = [ options.router.middleware ]
|
if (options.router && typeof options.router.middleware === 'string') options.router.middleware = [options.router.middleware]
|
||||||
if (options.router && typeof options.router.base === 'string') {
|
if (options.router && typeof options.router.base === 'string') {
|
||||||
this._routerBaseSpecified = true
|
this._routerBaseSpecified = true
|
||||||
}
|
}
|
||||||
if (typeof options.transition === 'string') options.transition = { name: options.transition }
|
if (typeof options.transition === 'string') options.transition = {name: options.transition}
|
||||||
this.options = _.defaultsDeep(options, defaults)
|
this.options = _.defaultsDeep(options, defaults)
|
||||||
// Ready variable
|
// Ready variable
|
||||||
this._ready = false
|
this._ready = false
|
||||||
@ -124,20 +127,25 @@ class Nuxt {
|
|||||||
// Add module integration
|
// Add module integration
|
||||||
this.module = new Module(this)
|
this.module = new Module(this)
|
||||||
// Init nuxt.js
|
// Init nuxt.js
|
||||||
this.ready()
|
this._ready = this.ready()
|
||||||
// Launch build in development but don't wait for him to be finished
|
|
||||||
if (this.dev) {
|
|
||||||
this.build()
|
|
||||||
}
|
|
||||||
// Return nuxt.js instance
|
// Return nuxt.js instance
|
||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
async ready () {
|
async ready () {
|
||||||
if (this._ready) return this
|
if (this._ready) {
|
||||||
|
await this._ready
|
||||||
|
return this
|
||||||
|
}
|
||||||
// Init modules
|
// Init modules
|
||||||
await this.module.ready()
|
await this.module.ready()
|
||||||
this._ready = true
|
// Launch build in development but don't wait for it to be finished
|
||||||
|
if (this.dev) {
|
||||||
|
this.build()
|
||||||
|
} else {
|
||||||
|
build.production.call(this)
|
||||||
|
}
|
||||||
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
close (callback) {
|
close (callback) {
|
||||||
|
@ -5,12 +5,16 @@ import serialize from 'serialize-javascript'
|
|||||||
import generateETag from 'etag'
|
import generateETag from 'etag'
|
||||||
import fresh from 'fresh'
|
import fresh from 'fresh'
|
||||||
import { getContext, setAnsiColors, encodeHtml } from './utils'
|
import { getContext, setAnsiColors, encodeHtml } from './utils'
|
||||||
|
|
||||||
const debug = require('debug')('nuxt:render')
|
const debug = require('debug')('nuxt:render')
|
||||||
// force blue color
|
// force blue color
|
||||||
debug.color = 4
|
debug.color = 4
|
||||||
setAnsiColors(ansiHTML)
|
setAnsiColors(ansiHTML)
|
||||||
|
|
||||||
export async function render (req, res) {
|
export async function render (req, res) {
|
||||||
|
// Wait for nuxt.js to be ready
|
||||||
|
await this.ready()
|
||||||
|
// Check if project is built for production
|
||||||
if (!this.renderer && !this.dev) {
|
if (!this.renderer && !this.dev) {
|
||||||
console.error('> No build files found, please run `nuxt build` before launching `nuxt start`') // eslint-disable-line no-console
|
console.error('> No build files found, please run `nuxt build` before launching `nuxt start`') // eslint-disable-line no-console
|
||||||
process.exit(1)
|
process.exit(1)
|
||||||
@ -23,8 +27,6 @@ export async function render (req, res) {
|
|||||||
}, 1000)
|
}, 1000)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
// Wait for nuxt.js to be ready
|
|
||||||
await this.ready()
|
|
||||||
// Get context
|
// Get context
|
||||||
const context = getContext(req, res)
|
const context = getContext(req, res)
|
||||||
res.statusCode = 200
|
res.statusCode = 200
|
||||||
@ -56,7 +58,7 @@ export async function render (req, res) {
|
|||||||
res.statusCode = 404
|
res.statusCode = 404
|
||||||
return res.end()
|
return res.end()
|
||||||
}
|
}
|
||||||
const { html, error, redirected, resourceHints } = await this.renderRoute(req.url, context)
|
const {html, error, redirected, resourceHints} = await this.renderRoute(req.url, context)
|
||||||
if (redirected) {
|
if (redirected) {
|
||||||
return html
|
return html
|
||||||
}
|
}
|
||||||
@ -66,27 +68,32 @@ export async function render (req, res) {
|
|||||||
// ETag header
|
// ETag header
|
||||||
if (!error && this.options.render.etag) {
|
if (!error && this.options.render.etag) {
|
||||||
const etag = generateETag(html, this.options.render.etag)
|
const etag = generateETag(html, this.options.render.etag)
|
||||||
if (fresh(req.headers, { etag })) {
|
if (fresh(req.headers, {etag})) {
|
||||||
res.statusCode = 304
|
res.statusCode = 304
|
||||||
res.end()
|
res.end()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res.setHeader('ETag', etag)
|
res.setHeader('ETag', etag)
|
||||||
}
|
}
|
||||||
|
// HTTP2 push headers
|
||||||
|
if (!error && this.options.render.http2.push) {
|
||||||
|
// Parse resourceHints to extract HTTP.2 prefetch/push headers
|
||||||
|
// https://w3c.github.io/preload/#server-push-http-2
|
||||||
|
const regex = /link rel="([^"]*)" href="([^"]*)" as="([^"]*)"/g
|
||||||
|
const pushAssets = []
|
||||||
|
let m
|
||||||
|
while (m = regex.exec(resourceHints)) { // eslint-disable-line no-cond-assign
|
||||||
|
const [_, rel, href, as] = m // eslint-disable-line no-unused-vars
|
||||||
|
if (rel === 'preload') {
|
||||||
|
pushAssets.push(`<${href}>; rel=${rel}; as=${as}`)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Pass with single Link header
|
||||||
|
// https://blog.cloudflare.com/http-2-server-push-with-multiple-assets-per-link-header
|
||||||
|
res.setHeader('Link', pushAssets.join(','))
|
||||||
|
}
|
||||||
res.setHeader('Content-Type', 'text/html; charset=utf-8')
|
res.setHeader('Content-Type', 'text/html; charset=utf-8')
|
||||||
res.setHeader('Content-Length', Buffer.byteLength(html))
|
res.setHeader('Content-Length', Buffer.byteLength(html))
|
||||||
// Parse resourceHints to extract HTTP.2 prefetch/push headers
|
|
||||||
// https://w3c.github.io/preload/#server-push-http-2
|
|
||||||
const regex = /link rel="([^"]*)" href="([^"]*)" as="([^"]*)"/g
|
|
||||||
const pushAssets = []
|
|
||||||
let m
|
|
||||||
while (m = regex.exec(resourceHints)) { // eslint-disable-line no-cond-assign
|
|
||||||
const [_, rel, href, as] = m // eslint-disable-line no-unused-vars
|
|
||||||
if (rel === 'preload') {
|
|
||||||
pushAssets.push(`<${href}>; rel=${rel}; as=${as}`)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res.setHeader('Link', pushAssets)
|
|
||||||
res.end(html, 'utf8')
|
res.end(html, 'utf8')
|
||||||
return html
|
return html
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
@ -95,7 +102,7 @@ export async function render (req, res) {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
const html = this.errorTemplate({
|
const html = this.errorTemplate({
|
||||||
/* istanbul ignore if */
|
/* istanbul ignore if */
|
||||||
error: err,
|
error: err,
|
||||||
stack: ansiHTML(encodeHtml(err.stack))
|
stack: ansiHTML(encodeHtml(err.stack))
|
||||||
})
|
})
|
||||||
@ -127,7 +134,7 @@ export async function renderRoute (url, context = {}) {
|
|||||||
}
|
}
|
||||||
const resourceHints = context.renderResourceHints()
|
const resourceHints = context.renderResourceHints()
|
||||||
HEAD += resourceHints + context.renderStyles()
|
HEAD += resourceHints + context.renderStyles()
|
||||||
APP += `<script type="text/javascript">window.__NUXT__=${serialize(context.nuxt, { isJSON: true })}</script>`
|
APP += `<script type="text/javascript">window.__NUXT__=${serialize(context.nuxt, {isJSON: true})}</script>`
|
||||||
APP += context.renderScripts()
|
APP += context.renderScripts()
|
||||||
const html = this.appTemplate({
|
const html = this.appTemplate({
|
||||||
HTML_ATTRS: 'data-n-head-ssr ' + m.htmlAttrs.text(),
|
HTML_ATTRS: 'data-n-head-ssr ' + m.htmlAttrs.text(),
|
||||||
@ -162,14 +169,15 @@ export async function renderAndGetWindow (url, opts = {}) {
|
|||||||
runScripts: 'dangerously',
|
runScripts: 'dangerously',
|
||||||
beforeParse (window) {
|
beforeParse (window) {
|
||||||
// Mock window.scrollTo
|
// Mock window.scrollTo
|
||||||
window.scrollTo = () => {}
|
window.scrollTo = () => {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (opts.virtualConsole !== false) {
|
if (opts.virtualConsole !== false) {
|
||||||
options.virtualConsole = new jsdom.VirtualConsole().sendTo(console)
|
options.virtualConsole = new jsdom.VirtualConsole().sendTo(console)
|
||||||
}
|
}
|
||||||
url = url || 'http://localhost:3000'
|
url = url || 'http://localhost:3000'
|
||||||
const { window } = await jsdom.JSDOM.fromURL(url, options)
|
const {window} = await jsdom.JSDOM.fromURL(url, options)
|
||||||
// If Nuxt could not be loaded (error from the server-side)
|
// If Nuxt could not be loaded (error from the server-side)
|
||||||
const nuxtExists = window.document.body.innerHTML.includes('window.__NUXT__')
|
const nuxtExists = window.document.body.innerHTML.includes('window.__NUXT__')
|
||||||
if (!nuxtExists) {
|
if (!nuxtExists) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "nuxt",
|
"name": "nuxt",
|
||||||
"version": "1.0.0-alpha2",
|
"version": "1.0.0-alpha.3",
|
||||||
"description": "A minimalistic framework for server-rendered Vue.js applications (inspired by Next.js)",
|
"description": "A minimalistic framework for server-rendered Vue.js applications (inspired by Next.js)",
|
||||||
"contributors": [
|
"contributors": [
|
||||||
{
|
{
|
||||||
|
Loading…
Reference in New Issue
Block a user