diff --git a/README.md b/README.md index 19b4648111..40ed8ee8bc 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@ Build Status Windows Build Status  Coverage Status - Downloads + Downloads Version License Gitter @@ -12,13 +12,87 @@ Support us - +

> Nuxt.js is a framework for server-rendered Vue applications (inspired by [Next.js](https://github.com/zeit/next.js)) ## 🚧 Under active development, [1.0](https://github.com/nuxt/nuxt.js/projects/1) will be released soon :fire: +## Sponsors + +Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/nuxtjs#sponsor)] + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ +## Backers + +Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/nuxtjs#backer)] + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

+ ## Links - 📘 Documentation: [https://nuxtjs.org](https://nuxtjs.org) @@ -172,75 +246,3 @@ Note: we recommend putting `.nuxt` in `.npmignore` or `.gitignore`. ## Roadmap https://github.com/nuxt/nuxt.js/projects/1 - -## Backers - -Support us with a monthly donation and help us continue our activities. [[Become a backer](https://opencollective.com/nuxtjs#backer)] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -## Sponsors - -Become a sponsor and get your logo on our README on Github with a link to your site. [[Become a sponsor](https://opencollective.com/nuxtjs#sponsor)] - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/lib/build.js b/lib/build.js index 5ad93f10ab..cc1e2b610a 100644 --- a/lib/build.js +++ b/lib/build.js @@ -223,7 +223,10 @@ async function generateRoutesAndFiles () { const files = await glob('pages/**/*.vue', {cwd: this.srcDir}) templateVars.router.routes = createRoutes(files, this.srcDir) } else { +<<<<<<< HEAD this.createRoutes = this.createRoutes.bind(this) +======= +>>>>>>> ac42ae599ec5878f0596305d4a4c9c195ff1e72c templateVars.router.routes = this.createRoutes(this.srcDir) } // router.extendRoutes method diff --git a/lib/module.js b/lib/module.js index 1febb849e5..90c980342e 100755 --- a/lib/module.js +++ b/lib/module.js @@ -74,6 +74,7 @@ class Module { if (this.modules.indexOf(moduleOpts) !== -1 || this.modules.indexOf(moduleOpts.src) !== -1) { return false } + this.modules.push(moduleOpts.src || moduleOpts) return this.addModule(moduleOpts) } @@ -102,16 +103,15 @@ class Module { console.error('[nuxt] Unable to resolve module', src) // eslint-disable-next-line no-console console.error(e) - return + process.exit(0) } // Validate module /* istanbul ignore if */ if (!(module instanceof Function)) { // eslint-disable-next-line no-console - return console.error(`[nuxt] Module [${originalSrc}] should export a function`) + console.error(`[nuxt] Module [${originalSrc}] should export a function`) + process.exit(1) } - // Add module to this.modules - this.modules.push(module) // Call module with `this` context and pass options return new Promise((resolve, reject) => { const result = module.call(this, options, err => { diff --git a/lib/render.js b/lib/render.js index f4e3af8fce..c1a3e7adc6 100644 --- a/lib/render.js +++ b/lib/render.js @@ -54,13 +54,14 @@ export async function render (req, res) { res.statusCode = 404 return res.end() } - const { html, error, redirected } = await this.renderRoute(req.url, context) + const { html, error, redirected, resourceHints } = await this.renderRoute(req.url, context) if (redirected) { return html } if (error) { res.statusCode = context.nuxt.error.statusCode || 500 } + // ETag header if (!error && this.options.render.etag) { const etag = generateETag(html, this.options.render.etag) if (fresh(req.headers, { etag })) { @@ -72,6 +73,18 @@ export async function render (req, res) { } 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) { @@ -106,7 +119,8 @@ export async function renderRoute (url, context = {}) { if (this._routerBaseSpecified) { HEAD += `` } - HEAD += context.renderResourceHints() + context.renderStyles() + const resourceHints = context.renderResourceHints() + HEAD += resourceHints + context.renderStyles() APP += `` APP += context.renderScripts() const html = this.appTemplate({ @@ -117,6 +131,7 @@ export async function renderRoute (url, context = {}) { }) return { html, + resourceHints, error: context.nuxt.error, redirected: context.redirected } diff --git a/test/basic.test.js b/test/basic.test.js index ed5d7f3de2..a8969289e6 100755 --- a/test/basic.test.js +++ b/test/basic.test.js @@ -144,6 +144,15 @@ test('/redirect2 status code', async t => { t.true(output.stderr[0].includes('Error: NOPE!')) }) +test('ETag Header', async t => { + const {headers: {etag}} = await rp(url('/stateless'), {resolveWithFullResponse: true}) + // Validate etag + t.regex(etag, /W\/".*"$/) + // Verify functionality + const error = await t.throws(rp(url('/stateless'), {headers: {'If-None-Match': etag}})) + t.is(error.statusCode, 304) +}) + // Close server and ask nuxt to stop listening to file changes test.after('Closing server and nuxt.js', t => { server.close() diff --git a/test/fixtures/module/modules/basic/index.js b/test/fixtures/module/modules/basic/index.js index 1fe62535ac..864007865b 100755 --- a/test/fixtures/module/modules/basic/index.js +++ b/test/fixtures/module/modules/basic/index.js @@ -22,5 +22,9 @@ module.exports = function basicModule (options, resolve) { // Do nothing! }) + // Require same module twice + this.requireModule('~/modules/empty/index.js') + this.requireModule('~/modules/empty/index.js') + resolve() } diff --git a/test/fixtures/module/modules/empty/index.js b/test/fixtures/module/modules/empty/index.js new file mode 100755 index 0000000000..b994d6d28a --- /dev/null +++ b/test/fixtures/module/modules/empty/index.js @@ -0,0 +1,4 @@ + +module.exports = function middlewareModule (options) { + // Empty module +} diff --git a/test/fixtures/module/modules/middleware/index.js b/test/fixtures/module/modules/middleware/index.js index f747712f6e..d8e21640ab 100755 --- a/test/fixtures/module/modules/middleware/index.js +++ b/test/fixtures/module/modules/middleware/index.js @@ -8,6 +8,8 @@ module.exports = function middlewareModule (options) { res.end('It works!') } }) + // Add local middleware js + this.addServerMiddleware('~/modules/middleware/log.js') // Add plain middleware this.addServerMiddleware((req, res, next) => { res.setHeader('x-nuxt', 'hello') diff --git a/test/fixtures/module/modules/middleware/log.js b/test/fixtures/module/modules/middleware/log.js new file mode 100755 index 0000000000..c8d2b3ebcb --- /dev/null +++ b/test/fixtures/module/modules/middleware/log.js @@ -0,0 +1,5 @@ +module.exports = function (req, res, next) { + // eslint-disable-next-line no-console + console.log(req.url) + next() +}