mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 08:33:53 +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:
|
||||
- if [[ `npm -v` != 3* ]]; then npm i -g npm@3; fi
|
||||
install:
|
||||
- npm install
|
||||
- npm run build
|
||||
- yarn install
|
||||
- yarn run build
|
||||
script:
|
||||
- npm test
|
||||
- yarn run test
|
||||
after_success:
|
||||
- npm run coverage
|
||||
- yarn run coverage
|
||||
|
@ -7,15 +7,16 @@ install:
|
||||
# Get the latest stable version of Node.js or io.js
|
||||
- ps: Install-Product node $env:nodejs_version
|
||||
# install modules
|
||||
- npm install
|
||||
- yarn install
|
||||
|
||||
# Post-install test scripts.
|
||||
test_script:
|
||||
# Output useful info for debugging.
|
||||
- node --version
|
||||
- npm --version
|
||||
- yarn --version
|
||||
# run tests
|
||||
- npm test
|
||||
- yarn run test
|
||||
|
||||
# Don't actually build.
|
||||
build: off
|
||||
|
@ -1,16 +1,13 @@
|
||||
module.exports = {
|
||||
loading: { color: 'cyan' },
|
||||
build: {
|
||||
vendor: ['vue-i18n']
|
||||
},
|
||||
router: {
|
||||
middleware: 'i18n'
|
||||
},
|
||||
plugins: [
|
||||
// Will inject the plugin in the $root app and also in the context as `i18n`
|
||||
{ src: '~plugins/i18n.js', injectAs: 'i18n' }
|
||||
],
|
||||
plugins: ['~plugins/i18n.js',],
|
||||
generate: {
|
||||
routes: ['/', '/about', '/fr', '/fr/about']
|
||||
},
|
||||
loading: { color: 'cyan' },
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "nuxt-i18n",
|
||||
"dependencies": {
|
||||
"nuxt": "latest",
|
||||
"nuxt": "1.0.0-alpha.3",
|
||||
"vue-i18n": "^7.0.0"
|
||||
},
|
||||
"scripts": {
|
||||
|
@ -19,6 +19,7 @@ const isDev = <%= isDev %>
|
||||
export default async (context) => {
|
||||
const { app, router<%= (store ? ', store' : '') %> } = await createApp(context)
|
||||
const _app = new Vue(app)
|
||||
const _noopApp = new Vue({ render: (h) => h('div') })
|
||||
// Add store to the context
|
||||
<%= (store ? 'context.store = store' : '') %>
|
||||
// Add route to the context
|
||||
@ -84,7 +85,7 @@ export default async (context) => {
|
||||
if (!context.nuxt.error) {
|
||||
await middlewareSeries(midd, ctx)
|
||||
}
|
||||
if (context.redirected) return _app
|
||||
if (context.redirected) return _noopApp
|
||||
// Set layout
|
||||
let layout = Components.length ? Components[0].options.layout : NuxtError.layout
|
||||
if (typeof layout === 'function') layout = layout(ctx)
|
||||
@ -109,7 +110,7 @@ export default async (context) => {
|
||||
if (!context.nuxt.error) {
|
||||
await middlewareSeries(midd, ctx)
|
||||
}
|
||||
if (context.redirected) return _app
|
||||
if (context.redirected) return _noopApp
|
||||
// Call .validate()
|
||||
let isValid = true
|
||||
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)) {
|
||||
this.options.build.publicPath = defaults.publicPath
|
||||
}
|
||||
}
|
||||
|
||||
export function production () {
|
||||
// Production, create server-renderer
|
||||
if (!this.dev) {
|
||||
webpackStats = {
|
||||
chunks: false,
|
||||
children: false,
|
||||
modules: false,
|
||||
colors: true
|
||||
}
|
||||
const serverConfig = getWebpackServerConfig.call(this)
|
||||
const bundlePath = join(serverConfig.output.path, 'server-bundle.json')
|
||||
const manifestPath = join(serverConfig.output.path, 'client-manifest.json')
|
||||
if (fs.existsSync(bundlePath) && fs.existsSync(manifestPath)) {
|
||||
const bundle = fs.readFileSync(bundlePath, 'utf8')
|
||||
const manifest = fs.readFileSync(manifestPath, 'utf8')
|
||||
createRenderer.call(this, JSON.parse(bundle), JSON.parse(manifest))
|
||||
addAppTemplate.call(this)
|
||||
}
|
||||
webpackStats = {
|
||||
chunks: false,
|
||||
children: false,
|
||||
modules: false,
|
||||
colors: true
|
||||
}
|
||||
const serverConfig = getWebpackServerConfig.call(this)
|
||||
const bundlePath = join(serverConfig.output.path, 'server-bundle.json')
|
||||
const manifestPath = join(serverConfig.output.path, 'client-manifest.json')
|
||||
if (fs.existsSync(bundlePath) && fs.existsSync(manifestPath)) {
|
||||
const bundle = fs.readFileSync(bundlePath, 'utf8')
|
||||
const manifest = fs.readFileSync(manifestPath, 'utf8')
|
||||
createRenderer.call(this, JSON.parse(bundle), JSON.parse(manifest))
|
||||
addAppTemplate.call(this)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -42,6 +42,10 @@ export default async function () {
|
||||
const s = Date.now()
|
||||
let errors = []
|
||||
/*
|
||||
** Wait for modules to be initialized
|
||||
*/
|
||||
await this.ready()
|
||||
/*
|
||||
** Set variables
|
||||
*/
|
||||
this.options.generate = _.defaultsDeep(this.options.generate, defaults)
|
||||
|
@ -2,9 +2,9 @@
|
||||
|
||||
import path from 'path'
|
||||
import fs from 'fs'
|
||||
import {uniq} from 'lodash'
|
||||
import { uniq } from 'lodash'
|
||||
import hash from 'hash-sum'
|
||||
import {chainFn, sequence} from './utils'
|
||||
import { chainFn, sequence } from './utils'
|
||||
|
||||
const debug = require('debug')('nuxt:module')
|
||||
|
||||
@ -12,17 +12,18 @@ class Module {
|
||||
constructor (nuxt) {
|
||||
this.nuxt = nuxt
|
||||
this.options = nuxt.options
|
||||
this.modules = []
|
||||
this.requiredModules = []
|
||||
this.initing = this.ready()
|
||||
}
|
||||
|
||||
async ready () {
|
||||
if (this.initing) {
|
||||
await this.initing
|
||||
return
|
||||
return this
|
||||
}
|
||||
// Install all modules in sequence
|
||||
await sequence(this.options.modules, this.addModule.bind(this))
|
||||
return this
|
||||
}
|
||||
|
||||
addVendor (vendor) {
|
||||
@ -81,14 +82,11 @@ class Module {
|
||||
}
|
||||
|
||||
requireModule (moduleOpts) {
|
||||
if (this.modules.indexOf(moduleOpts) !== -1 || this.modules.indexOf(moduleOpts.src) !== -1) {
|
||||
return false
|
||||
}
|
||||
this.modules.push(moduleOpts.src || moduleOpts)
|
||||
return this.addModule(moduleOpts)
|
||||
// Require once
|
||||
return this.addModule(moduleOpts, true)
|
||||
}
|
||||
|
||||
addModule (moduleOpts) {
|
||||
addModule (moduleOpts, requireOnce) {
|
||||
/* istanbul ignore if */
|
||||
if (!moduleOpts) {
|
||||
return
|
||||
@ -128,6 +126,19 @@ class Module {
|
||||
console.error(`[nuxt] Module [${originalSrc}] should export a function`)
|
||||
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
|
||||
return new Promise((resolve, reject) => {
|
||||
const result = module.call(this, options, err => {
|
||||
|
26
lib/nuxt.js
26
lib/nuxt.js
@ -51,6 +51,9 @@ class Nuxt {
|
||||
scrollBehavior: null
|
||||
},
|
||||
render: {
|
||||
http2: {
|
||||
push: false
|
||||
},
|
||||
static: {},
|
||||
gzip: {
|
||||
threshold: 0
|
||||
@ -66,11 +69,11 @@ class Nuxt {
|
||||
}
|
||||
// Sanitization
|
||||
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') {
|
||||
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)
|
||||
// Ready variable
|
||||
this._ready = false
|
||||
@ -124,20 +127,25 @@ class Nuxt {
|
||||
// Add module integration
|
||||
this.module = new Module(this)
|
||||
// Init nuxt.js
|
||||
this.ready()
|
||||
// Launch build in development but don't wait for him to be finished
|
||||
if (this.dev) {
|
||||
this.build()
|
||||
}
|
||||
this._ready = this.ready()
|
||||
// Return nuxt.js instance
|
||||
return this
|
||||
}
|
||||
|
||||
async ready () {
|
||||
if (this._ready) return this
|
||||
if (this._ready) {
|
||||
await this._ready
|
||||
return this
|
||||
}
|
||||
// Init modules
|
||||
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) {
|
||||
|
@ -5,12 +5,16 @@ import serialize from 'serialize-javascript'
|
||||
import generateETag from 'etag'
|
||||
import fresh from 'fresh'
|
||||
import { getContext, setAnsiColors, encodeHtml } from './utils'
|
||||
|
||||
const debug = require('debug')('nuxt:render')
|
||||
// force blue color
|
||||
debug.color = 4
|
||||
setAnsiColors(ansiHTML)
|
||||
|
||||
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) {
|
||||
console.error('> No build files found, please run `nuxt build` before launching `nuxt start`') // eslint-disable-line no-console
|
||||
process.exit(1)
|
||||
@ -23,8 +27,6 @@ export async function render (req, res) {
|
||||
}, 1000)
|
||||
})
|
||||
}
|
||||
// Wait for nuxt.js to be ready
|
||||
await this.ready()
|
||||
// Get context
|
||||
const context = getContext(req, res)
|
||||
res.statusCode = 200
|
||||
@ -56,7 +58,7 @@ export async function render (req, res) {
|
||||
res.statusCode = 404
|
||||
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) {
|
||||
return html
|
||||
}
|
||||
@ -66,27 +68,32 @@ export async function render (req, res) {
|
||||
// ETag header
|
||||
if (!error && 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.end()
|
||||
return
|
||||
}
|
||||
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-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')
|
||||
return html
|
||||
} catch (err) {
|
||||
@ -95,7 +102,7 @@ export async function render (req, res) {
|
||||
return err
|
||||
}
|
||||
const html = this.errorTemplate({
|
||||
/* istanbul ignore if */
|
||||
/* istanbul ignore if */
|
||||
error: err,
|
||||
stack: ansiHTML(encodeHtml(err.stack))
|
||||
})
|
||||
@ -127,7 +134,7 @@ export async function renderRoute (url, context = {}) {
|
||||
}
|
||||
const resourceHints = context.renderResourceHints()
|
||||
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()
|
||||
const html = this.appTemplate({
|
||||
HTML_ATTRS: 'data-n-head-ssr ' + m.htmlAttrs.text(),
|
||||
@ -162,14 +169,15 @@ export async function renderAndGetWindow (url, opts = {}) {
|
||||
runScripts: 'dangerously',
|
||||
beforeParse (window) {
|
||||
// Mock window.scrollTo
|
||||
window.scrollTo = () => {}
|
||||
window.scrollTo = () => {
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opts.virtualConsole !== false) {
|
||||
options.virtualConsole = new jsdom.VirtualConsole().sendTo(console)
|
||||
}
|
||||
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)
|
||||
const nuxtExists = window.document.body.innerHTML.includes('window.__NUXT__')
|
||||
if (!nuxtExists) {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"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)",
|
||||
"contributors": [
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user