Add nuxt-build and nuxt-start, build:false and dev option

This commit is contained in:
Sébastien Chopin 2016-11-09 23:59:41 +01:00
parent 78d81228f4
commit 18a2b57655
20 changed files with 343 additions and 227 deletions

View File

@ -56,7 +56,7 @@ So far, we get:
## Using nuxt.js programmatically
Nuxt is built on the top of ES2015, which makes the code more enjoyable and cleaner to read. It doesn't make use of any transpilers and depends upon Core V8 implemented features.
For these reasons, Nuxt.js targets Node.js `4.0` or higher (you might want to launch node with the `--harmony-proxies` flag if you running `node <= 6.5.0` )
For these reasons, nuxt.js targets Node.js `4.0` or higher (you might want to launch node with the `--harmony-proxies` flag if you running `node <= 6.5.0` )
```js
const Nuxt = require('nuxt')
@ -115,3 +115,30 @@ cd node_modules/nuxt/
bin/nuxt examples/hello-world
# Go to http://localhost:3000
```
## Production deployment
To deploy, instead of running next, you probably want to build ahead of time. Therefore, building and starting are separate commands:
```bash
nuxt build
nuxt start
```
For example, to deploy with [`now`](https://zeit.co/now) a `package.json` like follows is recommended:
```json
{
"name": "my-app",
"dependencies": {
"next": "latest"
},
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start"
}
}
```
Then run `now` and enjoy!
Note: we recommend putting `.nuxt` in `.npmignore` or `.gitignore`.

View File

@ -3,10 +3,12 @@
const { join } = require('path')
const { spawn } = require('cross-spawn')
const defaultCommand = 'start'
const defaultCommand = 'dev'
const commands = new Set([
defaultCommand,
'init'
'init',
'build',
'start'
])
let cmd = process.argv[2]

27
bin/nuxt-build Executable file
View File

@ -0,0 +1,27 @@
#!/usr/bin/env node
const fs = require('fs')
const Nuxt = require('../')
const { resolve } = require('path')
const rootDir = resolve(process.argv.slice(2)[0] || '.')
const nuxtConfigFile = resolve(rootDir, 'nuxt.config.js')
let options = {}
if (fs.existsSync(nuxtConfigFile)) {
options = require(nuxtConfigFile)
}
if (typeof options.rootDir !== 'string') {
options.rootDir = rootDir
}
options.dev = false // Create production build when calling `nuxt build`
console.log('[nuxt] Building...')
new Nuxt(options)
.then((nuxt) => {
console.log('[nuxt] Building done')
})
.catch((err) => {
console.error(err)
process.exit()
})

26
bin/nuxt-dev Executable file
View File

@ -0,0 +1,26 @@
#!/usr/bin/env node
const fs = require('fs')
const Nuxt = require('../')
const Server = require('../lib/server')
const { resolve } = require('path')
const rootDir = resolve(process.argv.slice(2)[0] || '.')
const nuxtConfigFile = resolve(rootDir, 'nuxt.config.js')
let options = {}
if (fs.existsSync(nuxtConfigFile)) {
options = require(nuxtConfigFile)
}
if (typeof options.rootDir !== 'string') {
options.rootDir = rootDir
}
new Nuxt(options)
.then((nuxt) => {
new Server(nuxt)
.listen(process.env.PORT, process.env.HOST)
})
.catch((err) => {
console.error(err)
process.exit()
})

View File

@ -1,11 +1,8 @@
#!/usr/bin/env node
const http = require('http')
const co = require('co')
const fs = require('fs')
const pify = require('pify')
const serveStatic = require('serve-static')
const Nuxt = require('../')
const Server = require('../lib/server')
const { resolve } = require('path')
const rootDir = resolve(process.argv.slice(2)[0] || '.')
@ -18,6 +15,9 @@ if (typeof options.rootDir !== 'string') {
options.rootDir = rootDir
}
options.build = false // Disable building
options.dev = false // Force production mode (no webpack middlewares called)
new Nuxt(options)
.then((nuxt) => {
new Server(nuxt)
@ -27,43 +27,3 @@ new Nuxt(options)
console.error(err)
process.exit()
})
class Server {
constructor (nuxt) {
this.server = http.createServer(this.handle.bind(this))
this.serveStatic = pify(serveStatic(resolve(rootDir, 'static')))
this.nuxt = nuxt
return this
}
handle (req, res) {
const method = req.method.toUpperCase()
const self = this
if (method !== 'GET' && method !== 'HEAD') {
return this.nuxt.render(req, res)
}
co(function * () {
if (req.url.includes('/static/')) {
const url = req.url
req.url = req.url.replace('/static/', '/')
yield self.serveStatic(req, res)
req.url = url
}
})
.then(() => {
// File not found
this.nuxt.render(req, res)
})
}
listen (port, host) {
host = host || 'localhost'
port = port || 3000
this.server.listen(port, host, () => {
console.log('Ready on http://%s:%s', host, port)
})
}
}

View File

@ -27,19 +27,20 @@ module.exports = {
To see the demo working:
```bash
npm install
npm start
npm run dev
```
Go to [http://localhost:8080](http://localhost:8080) and navigate inside the app.
Go to [http://localhost:3000](http://localhost:3000) and navigate inside the app.
## Production
In production, they will be minified and extracted in a file named `styles.css` and added in the `<head>` of the page.
To launch the demo in production mode so you can see the ``<head>` populated with the `<link>` tag:
To launch the demo in production mode so you can see the `<head>` populated with the `<link>` tag:
```bash
NODE_ENV=production npm start
npm run build
npm start
```
Go to [http://localhost:8080](http://localhost:8080) and check the source code.
Go to [http://localhost:3000](http://localhost:3000) and check the source code.

View File

@ -9,6 +9,8 @@
"sass-loader": "^4.0.2"
},
"scripts": {
"start": "nuxt"
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start"
}
}

View File

@ -1,4 +1,4 @@
# Using external modules and plugings with Nuxt.js
# Using external modules and plugings with nuxt.js
## Configuration: `build.vendor`

View File

@ -11,10 +11,10 @@ let server = null
// Init nuxt.js and create server listening on localhost:4000
test.before('Init nuxt.js', (t) => {
process.env.NODE_ENV = 'test'
const Nuxt = require('../../../')
const options = {
rootDir: resolve(__dirname, '..')
rootDir: resolve(__dirname, '..'),
dev: false
}
return new Nuxt(options)
.then(function (_nuxt) {
@ -65,9 +65,11 @@ test('Route / exits and render HTML', async t => {
*/
test('Route / exits and render HTML', async t => {
const window = await renderAndGetWindow('/')
t.is(window.document.querySelector('p').textContent, 'Hello world!')
t.is(window.document.querySelector('p').className, 'red-color')
t.true(window.document.querySelectorAll('style')[2].textContent.includes('.red-color {\n color: red;\n}'))
const element = window.document.querySelector('.red-color')
t.not(element, null)
t.is(element.textContent, 'Hello world!')
t.is(element.className, 'red-color')
t.is(window.getComputedStyle(element).color, 'red')
})
// Close server and ask nuxt to stop listening to file changes

View File

@ -176,5 +176,5 @@ Promise.all(resolveComponents)
}
})
.catch((err) => {
console.error('[Nuxt.js] Cannot load components', err)
console.error('[nuxt.js] Cannot load components', err)
})

View File

@ -4,7 +4,7 @@ import { pick } from 'lodash'
import { app, router<%= (store ? ', store' : '') %> } from './index'
import { getMatchedComponents, getContext } from './utils'
const isDev = process.env.NODE_ENV !== 'production'
const isDev = <%= isDev %>
const _app = new Vue(app)
// This exported function will be called by `bundleRenderer`.
@ -54,7 +54,7 @@ export default context => {
}))
.then((res) => {
<% if (isDev) { %>
debug('Data fetch ' + context.req.url + ': ' + (Date.now() - s) + 'ms')
debug('Data fetching ' + context.req.url + ': ' + (Date.now() - s) + 'ms')
<% } %>
// datas are the first row of each
context.nuxt.data = res.map((tab) => tab[0])

View File

@ -42,21 +42,25 @@ const defaultsLoaders = [
]
module.exports = function * () {
if (this.options.build === false) {
return Promise.resolve()
}
const noBuild = this.options.build === false
// Defaults build options
if (this.options.build && Array.isArray(this.options.build.loaders)) {
this.options.build = _.defaultsDeep(this.options.build, defaults)
} else {
this.options.build = _.defaultsDeep(this.options.build, defaults, { loaders: defaultsLoaders })
}
if (noBuild) {
const serverConfig = getWebpackServerConfig.call(this)
const bundlePath = join(serverConfig.output.path, serverConfig.output.filename)
createRenderer.call(this, fs.readFileSync(bundlePath, 'utf8'))
return Promise.resolve()
}
/*
** Check if pages dir exists and warn if not
*/
if (!fs.existsSync(join(this.dir, 'pages'))) {
if (fs.existsSync(join(this.dir, '..', 'pages'))) {
console.error('> No `pages` directory found. Did you mean to run `next` in the parent (`../`) directory?')
console.error('> No `pages` directory found. Did you mean to run `nuxt` in the parent (`../`) directory?')
} else {
console.error('> Couldn\'t find a `pages` directory. Please create one under the project root')
}
@ -75,9 +79,11 @@ module.exports = function * () {
/*
** Create .nuxt/, .nuxt/components and .nuxt/dist folders
*/
yield del(r(this.dir, '.nuxt'), { force: process.env.NODE_ENV === 'test' })
try {
yield del(r(this.dir, '.nuxt'))
} catch (e) {}
yield mkdirp(r(this.dir, '.nuxt/components'))
if (this.isProd) {
if (!this.dev) {
yield mkdirp(r(this.dir, '.nuxt/dist'))
}
/*
@ -116,24 +122,24 @@ module.exports = function * () {
'components/Loading.vue'
]
let templateVars = {
isDev: this.isDev,
isDev: this.dev,
store: this.options.store,
css: this.options.css,
plugins: this.options.plugins.map((p) => r(this.dir, p)),
loading: (this.options.loading === 'string' ? r(this.dir, this.options.loading) : this.options.loading),
components: {
Loading: r(__dirname, '..', 'app', 'components', 'Loading.vue'),
ErrorPage: r(__dirname, '..', '..', 'pages', (this.isDev ? '_error-debug.vue' : '_error.vue'))
ErrorPage: r(__dirname, '..', '..', 'pages', (this.dev ? '_error-debug.vue' : '_error.vue'))
},
routes: this.options.routes
}
if (this.options.store) {
templateVars.storePath = r(this.dir, 'store')
}
if (this.isDev && files.includes('pages/_error-debug.vue')) {
if (this.dev && files.includes('pages/_error-debug.vue')) {
templateVars.components.ErrorPage = r(this.dir, 'pages/_error-debug.vue')
}
if (!this.isDev && files.includes('pages/_error.vue')) {
if (!this.dev && files.includes('pages/_error.vue')) {
templateVars.components.ErrorPage = r(this.dir, 'pages/_error.vue')
}
const readFile = pify(fs.readFile)
@ -151,7 +157,7 @@ module.exports = function * () {
/*
** Generate .nuxt/dist/ files
*/
if (this.isDev) {
if (this.dev) {
debug('Adding webpack middlewares...')
createWebpackMiddlewares.call(this)
webpackWatchAndUpdate.call(this)
@ -164,66 +170,14 @@ module.exports = function * () {
}
}
function addGlobalWebpackConfig (config) {
const nodeModulesDir = join(__dirname, '..', '..', 'node_modules')
config.resolve = {
modules: [
nodeModulesDir,
join(this.dir, 'node_modules')
]
}
config.resolveLoader = {
modules: [
nodeModulesDir,
join(this.dir, 'node_modules')
]
}
config.module.rules = config.module.rules.concat(this.options.build.loaders)
return config
}
function getWebpackClientConfig () {
var config = require(r(__dirname, 'webpack', 'client.config.js'))
config = _.cloneDeep(config)
// Entry
config.entry.app = r(this.dir, '.nuxt', 'client.js')
// Add vendors
if (this.options.store) config.entry.vendor.push('vuex')
config.entry.vendor = config.entry.vendor.concat(this.options.build.vendor)
// extract vendor chunks for better caching
config.plugins.push(
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: this.options.build.filenames.vendor
})
)
// Output
config.output.path = r(this.dir, '.nuxt', 'dist')
config.output.filename = this.options.build.filenames.app
// Extract text plugin
if (this.isProd) {
const ExtractTextPlugin = require('extract-text-webpack-plugin')
let plugin = config.plugins.find((plugin) => plugin instanceof ExtractTextPlugin)
if (plugin) plugin.filename = this.options.build.filenames.css
}
return addGlobalWebpackConfig.call(this, config)
const clientConfigPath = r(__dirname, 'webpack', 'client.config.js')
return require(clientConfigPath).call(this)
}
function getWebpackServerConfig () {
var config = require(r(__dirname, 'webpack', 'server.config.js'))
config = _.cloneDeep(config)
// Entry
config.entry = r(this.dir, '.nuxt', 'server.js')
// Output
config.output.path = r(this.dir, '.nuxt', 'dist')
// Externals
config.externals = Object.keys(require(r(__dirname, '..', '..', 'package.json')).dependencies || {})
const projectPackageJson = r(this.dir, 'package.json')
if (fs.existsSync(projectPackageJson)) {
config.externals = config.externals.concat(Object.keys(require(r(this.dir, 'package.json')).dependencies || {}))
}
config.externals = _.uniq(config.externals)
return addGlobalWebpackConfig.call(this, config)
const configServerPath = r(__dirname, 'webpack', 'server.config.js')
return require(configServerPath).call(this)
}
function createWebpackMiddlewares () {
@ -270,7 +224,7 @@ function webpackRunClient () {
const serverCompiler = webpack(clientConfig)
serverCompiler.run((err, stats) => {
if (err) return reject(err)
console.log('[webpack:build:client]\n', stats.toString({ chunks: false, colors: true }))
console.log('[nuxt:build:client]\n', stats.toString({ chunks: false, colors: true }))
resolve()
})
})
@ -282,7 +236,7 @@ function webpackRunServer () {
const serverCompiler = webpack(serverConfig)
serverCompiler.run((err, stats) => {
if (err) return reject(err)
console.log('[webpack:build:server]\n', stats.toString({ chunks: false, colors: true }))
console.log('[nuxt:build:server]\n', stats.toString({ chunks: false, colors: true }))
const bundlePath = join(serverConfig.output.path, serverConfig.output.filename)
createRenderer.call(this, fs.readFileSync(bundlePath, 'utf8'))
resolve()

View File

@ -1,4 +1,5 @@
const vueLoaderConfig = require('./vue-loader.config')
const { join } = require('path')
/*
|--------------------------------------------------------------------------
@ -8,29 +9,49 @@ const vueLoaderConfig = require('./vue-loader.config')
| webpack config files
|--------------------------------------------------------------------------
*/
module.exports = {
devtool: 'source-map',
entry: {
vendor: ['vue', 'vue-router', 'vue-meta', 'es6-promise', 'es6-object-assign']
},
output: {
publicPath: '/_nuxt/'
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue',
options: vueLoaderConfig
},
{
test: /\.js$/,
loader: 'babel',
exclude: /node_modules/,
options: {
presets: ['es2015', 'stage-2']
module.exports = function () {
const nodeModulesDir = join(__dirname, '..', '..', '..', 'node_modules')
let config = {
devtool: 'source-map',
entry: {
vendor: ['vue', 'vue-router', 'vue-meta', 'es6-promise', 'es6-object-assign']
},
output: {
publicPath: '/_nuxt/'
},
resolve: {
modules: [
nodeModulesDir,
join(this.dir, 'node_modules')
]
},
resolveLoader: {
modules: [
nodeModulesDir,
join(this.dir, 'node_modules')
]
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue',
options: vueLoaderConfig.call(this)
},
{
test: /\.js$/,
loader: 'babel',
exclude: /node_modules/,
options: {
presets: ['es2015', 'stage-2']
}
}
}
]
]
}
}
// Add nuxt build loaders (can be configured in nuxt.config.js)
config.module.rules = config.module.rules.concat(this.options.build.loaders)
// Return config
return config
}

View File

@ -1,6 +1,7 @@
const webpack = require('webpack')
const ExtractTextPlugin = require('extract-text-webpack-plugin')
const base = require('./base.config')
const vueConfig = require('./vue-loader.config')
const { resolve } = require('path')
/*
|--------------------------------------------------------------------------
@ -12,47 +13,55 @@ const vueConfig = require('./vue-loader.config')
| In production, will generate public/dist/style.css
|--------------------------------------------------------------------------
*/
module.exports = function () {
let config = base.call(this)
const config = Object.assign({}, base, {
plugins: (base.plugins || []).concat([
// Entry
config.entry.app = resolve(this.dir, '.nuxt', 'client.js')
// Add vendors
if (this.options.store) {
config.entry.vendor.push('vuex')
}
config.entry.vendor = config.entry.vendor.concat(this.options.build.vendor)
// Output
config.output.path = resolve(this.dir, '.nuxt', 'dist')
config.output.filename = this.options.build.filenames.app
// Webpack plugins
config.plugins = (config.plugins || []).concat([
// strip comments in Vue code
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
'process.env.NODE_ENV': JSON.stringify(this.dev ? 'development' : 'production'),
'process.BROWSER': true
}),
// Extract vendor chunks for better caching
new webpack.optimize.CommonsChunkPlugin({
name: 'vendor',
filename: this.options.build.filenames.vendor
})
])
})
if (process.env.NODE_ENV === 'production') {
// Use ExtractTextPlugin to extract CSS into a single file
// so it's applied on initial render
const ExtractTextPlugin = require('extract-text-webpack-plugin')
// vueConfig is already included in the config via LoaderOptionsPlugin
// here we overwrite the loader config for <style lang='stylus'>
// so they are extracted.
vueConfig.loaders.css = ExtractTextPlugin.extract({ loader: 'css-loader' })
vueConfig.loaders.scss = ExtractTextPlugin.extract({ loader: 'css-loader!sass-loader', fallbackLoader: 'vue-style-loader' })
vueConfig.loaders.sass = ExtractTextPlugin.extract({ loader: 'css-loader!sass-loader?indentedSyntax', fallbackLoader: 'vue-style-loader' })
vueConfig.loaders.stylus = ExtractTextPlugin.extract({ loader: 'css-loader!stylus-loader', fallbackLoader: 'vue-style-loader' })
vueConfig.loaders.less = ExtractTextPlugin.extract({ loader: 'css-loader!less-loader', fallbackLoader: 'vue-style-loader' })
config.plugins.push(
new ExtractTextPlugin({
filename: 'style.css',
allChunks: true
}),
// this is needed in webpack 2 for minifying CSS
new webpack.LoaderOptionsPlugin({
minimize: true
}),
// minify JS
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
)
// Production client build
if (!this.dev) {
config.plugins.push(
// Use ExtractTextPlugin to extract CSS into a single file
new ExtractTextPlugin({
filename: this.options.build.filenames.css,
allChunks: true
}),
// This is needed in webpack 2 for minifying CSS
new webpack.LoaderOptionsPlugin({
minimize: true
}),
// Minify JS
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
})
)
}
return config
}
module.exports = config

View File

@ -1,23 +1,44 @@
const webpack = require('webpack')
const base = require('./base.config')
const { uniq } = require('lodash')
const { existsSync } = require('fs')
const { resolve } = require('path')
/*
|--------------------------------------------------------------------------
| Webpack Server Config
|--------------------------------------------------------------------------
*/
module.exports = Object.assign({}, base, {
target: 'node',
devtool: false,
output: Object.assign({}, base.output, {
filename: 'server-bundle.js',
libraryTarget: 'commonjs2'
}),
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
'process.env.VUE_ENV': '"server"',
'process.BROWSER': false
})
]
})
module.exports = function () {
let config = base.call(this)
config = Object.assign(config, {
target: 'node',
devtool: false,
entry: resolve(this.dir, '.nuxt', 'server.js'),
output: Object.assign({}, base.output, {
path: resolve(this.dir, '.nuxt', 'dist'),
filename: 'server-bundle.js',
libraryTarget: 'commonjs2'
}),
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(this.dev ? 'development' : 'production'),
'process.env.VUE_ENV': '"server"',
'process.BROWSER': false
})
]
})
// Externals
const nuxtPackageJson = require(resolve(__dirname, '..', '..', '..', 'package.json'))
const projectPackageJson = resolve(this.dir, 'package.json')
config.externals = Object.keys(nuxtPackageJson.dependencies || {})
if (existsSync(projectPackageJson)) {
config.externals = config.externals.concat(Object.keys(require(projectPackageJson).dependencies || {}))
}
config.externals = uniq(config.externals)
// Return config
return config
}

View File

@ -1,16 +1,31 @@
module.exports = {
postcss: [
require('autoprefixer')({
browsers: ['last 3 versions']
})
],
loaders: {
'js': 'babel-loader?presets[]=es2015&presets[]=stage-2',
'postcss': 'vue-style-loader!css-loader',
'less': 'vue-style-loader!css-loader!less-loader',
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax',
'scss': 'vue-style-loader!css-loader!sass-loader',
'stylus': 'vue-style-loader!css-loader!stylus-loader',
'styl': 'vue-style-loader!css-loader!stylus-loader'
module.exports = function () {
let config = {
postcss: [
require('autoprefixer')({
browsers: ['last 3 versions']
})
],
loaders: {
'js': 'babel-loader?presets[]=es2015&presets[]=stage-2',
'postcss': 'vue-style-loader!css-loader',
'less': 'vue-style-loader!css-loader!less-loader',
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax',
'scss': 'vue-style-loader!css-loader!sass-loader',
'stylus': 'vue-style-loader!css-loader!stylus-loader',
'styl': 'vue-style-loader!css-loader!stylus-loader'
}
}
if (!this.dev) {
// Use ExtractTextPlugin to extract CSS into a single file
const ExtractTextPlugin = require('extract-text-webpack-plugin')
config.loaders.css = ExtractTextPlugin.extract({ loader: 'css-loader' })
config.loaders.scss = ExtractTextPlugin.extract({ loader: 'css-loader!sass-loader', fallbackLoader: 'vue-style-loader' })
config.loaders.sass = ExtractTextPlugin.extract({ loader: 'css-loader!sass-loader?indentedSyntax', fallbackLoader: 'vue-style-loader' })
config.loaders.stylus = ExtractTextPlugin.extract({ loader: 'css-loader!stylus-loader', fallbackLoader: 'vue-style-loader' })
config.loaders.less = ExtractTextPlugin.extract({ loader: 'css-loader!less-loader', fallbackLoader: 'vue-style-loader' })
}
// Return the config
return config
}

View File

@ -17,6 +17,7 @@ class Nuxt {
constructor (options = {}, cb) {
var defaults = {
dev: true,
routes: [],
plugins: [],
css: [],
@ -32,8 +33,7 @@ class Nuxt {
if (options.loading === true) delete options.loading
this.options = _.defaultsDeep(options, defaults)
// Env variables
this.isProd = process.env.NODE_ENV === 'production'
this.isDev = !process.env.NODE_ENV || process.env.NODE_ENV === 'development'
this.dev = this.options.dev
this.dir = (typeof options.rootDir === 'string' && options.rootDir ? options.rootDir : process.cwd())
// Template
this.appTemplate = _.template(fs.readFileSync(resolve(__dirname, 'views', 'app.html'), 'utf8'), {
@ -70,7 +70,7 @@ class Nuxt {
const self = this
const context = getContext(req, res)
co(function * () {
if (self.isDev) {
if (self.dev) {
// Call webpack middlewares only in development
yield self.webpackDevMiddleware(req, res)
yield self.webpackHotMiddleware(req, res)
@ -84,7 +84,7 @@ class Nuxt {
}
})
.then(() => {
if (this.isDev && req.url.includes('/_nuxt/') && req.url.includes('.hot-update.json')) {
if (this.dev && req.url.includes('/_nuxt/') && req.url.includes('.hot-update.json')) {
res.statusCode = 404
return res.end()
}
@ -115,7 +115,7 @@ class Nuxt {
context.nuxt.error = { statusCode: 500, message: context.nuxt.error.message }
}
const app = self.appTemplate({
isProd: self.isProd, // Use to add the extracted CSS <link> in production
dev: self.dev, // Use to add the extracted CSS <link> in production
APP: html,
context: context,
files: {

49
lib/server.js Normal file
View File

@ -0,0 +1,49 @@
'use strict'
const http = require('http')
const co = require('co')
const pify = require('pify')
const serveStatic = require('serve-static')
const { resolve } = require('path')
class Server {
constructor (nuxt) {
this.server = http.createServer(this.handle.bind(this))
this.serveStatic = pify(serveStatic(resolve(nuxt.dir, 'static')))
this.nuxt = nuxt
return this
}
handle (req, res) {
const method = req.method.toUpperCase()
const self = this
if (method !== 'GET' && method !== 'HEAD') {
return this.nuxt.render(req, res)
}
co(function * () {
if (req.url.includes('/static/')) {
const url = req.url
req.url = req.url.replace('/static/', '/')
yield self.serveStatic(req, res)
req.url = url
}
})
.then(() => {
// File not found
this.nuxt.render(req, res)
})
}
listen (port, host) {
host = host || 'localhost'
port = port || 3000
this.server.listen(port, host, () => {
console.log('Ready on http://%s:%s', host, port)
})
}
}
module.exports = Server

View File

@ -8,7 +8,7 @@
<html>
<head>
${title.toString()}
<% if (isProd) { %><link rel="stylesheet" href="<%= files.css %>"><% } %>
<% if (!dev) { %><link rel="stylesheet" href="<%= files.css %>"><% } %>
</head>
<body>
<%= APP %>

View File

@ -25,7 +25,7 @@ test(async t => {
test(async t => {
const html = await (render('/head'))
t.true(html.includes('<meta content="my meta" class="next-head"/>'))
t.true(html.includes('<meta content="my meta" class="nuxt-head"/>'))
t.true(html.includes('<div><h1>I can haz meta tags</h1></div>'))
})