mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-27 08:02:01 +00:00
Merge remote-tracking branch 'nuxt/master'
This commit is contained in:
commit
982e49e0aa
29
README.md
29
README.md
@ -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`.
|
||||
|
6
bin/nuxt
6
bin/nuxt
@ -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
27
bin/nuxt-build
Executable 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
26
bin/nuxt-dev
Executable 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()
|
||||
})
|
@ -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)
|
||||
})
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -9,6 +9,8 @@
|
||||
"sass-loader": "^4.0.2"
|
||||
},
|
||||
"scripts": {
|
||||
"start": "nuxt"
|
||||
"dev": "nuxt",
|
||||
"build": "nuxt build",
|
||||
"start": "nuxt start"
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Using external modules and plugings with Nuxt.js
|
||||
# Using external modules and plugings with nuxt.js
|
||||
|
||||
## Configuration: `build.vendor`
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
})
|
||||
|
@ -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])
|
||||
|
@ -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()
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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
|
||||
}
|
||||
|
10
lib/nuxt.js
10
lib/nuxt.js
@ -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
49
lib/server.js
Normal 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
|
@ -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 %>
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "nuxt",
|
||||
"version": "0.2.5",
|
||||
"version": "0.2.6",
|
||||
"description": "A minimalistic framework for server-rendered Vue.js applications (inspired by Next.js)",
|
||||
"main": "index.js",
|
||||
"license": "MIT",
|
||||
|
@ -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>'))
|
||||
})
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user