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
|
## 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.
|
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
|
```js
|
||||||
const Nuxt = require('nuxt')
|
const Nuxt = require('nuxt')
|
||||||
@ -115,3 +115,30 @@ cd node_modules/nuxt/
|
|||||||
bin/nuxt examples/hello-world
|
bin/nuxt examples/hello-world
|
||||||
# Go to http://localhost:3000
|
# 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 { join } = require('path')
|
||||||
const { spawn } = require('cross-spawn')
|
const { spawn } = require('cross-spawn')
|
||||||
|
|
||||||
const defaultCommand = 'start'
|
const defaultCommand = 'dev'
|
||||||
const commands = new Set([
|
const commands = new Set([
|
||||||
defaultCommand,
|
defaultCommand,
|
||||||
'init'
|
'init',
|
||||||
|
'build',
|
||||||
|
'start'
|
||||||
])
|
])
|
||||||
|
|
||||||
let cmd = process.argv[2]
|
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
|
#!/usr/bin/env node
|
||||||
|
|
||||||
const http = require('http')
|
|
||||||
const co = require('co')
|
|
||||||
const fs = require('fs')
|
const fs = require('fs')
|
||||||
const pify = require('pify')
|
|
||||||
const serveStatic = require('serve-static')
|
|
||||||
const Nuxt = require('../')
|
const Nuxt = require('../')
|
||||||
|
const Server = require('../lib/server')
|
||||||
const { resolve } = require('path')
|
const { resolve } = require('path')
|
||||||
|
|
||||||
const rootDir = resolve(process.argv.slice(2)[0] || '.')
|
const rootDir = resolve(process.argv.slice(2)[0] || '.')
|
||||||
@ -18,6 +15,9 @@ if (typeof options.rootDir !== 'string') {
|
|||||||
options.rootDir = rootDir
|
options.rootDir = rootDir
|
||||||
}
|
}
|
||||||
|
|
||||||
|
options.build = false // Disable building
|
||||||
|
options.dev = false // Force production mode (no webpack middlewares called)
|
||||||
|
|
||||||
new Nuxt(options)
|
new Nuxt(options)
|
||||||
.then((nuxt) => {
|
.then((nuxt) => {
|
||||||
new Server(nuxt)
|
new Server(nuxt)
|
||||||
@ -27,43 +27,3 @@ new Nuxt(options)
|
|||||||
console.error(err)
|
console.error(err)
|
||||||
process.exit()
|
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:
|
To see the demo working:
|
||||||
```bash
|
```bash
|
||||||
npm install
|
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
|
## Production
|
||||||
|
|
||||||
In production, they will be minified and extracted in a file named `styles.css` and added in the `<head>` of the page.
|
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
|
```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"
|
"sass-loader": "^4.0.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"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`
|
## Configuration: `build.vendor`
|
||||||
|
|
||||||
|
@ -11,10 +11,10 @@ let server = null
|
|||||||
|
|
||||||
// Init nuxt.js and create server listening on localhost:4000
|
// Init nuxt.js and create server listening on localhost:4000
|
||||||
test.before('Init nuxt.js', (t) => {
|
test.before('Init nuxt.js', (t) => {
|
||||||
process.env.NODE_ENV = 'test'
|
|
||||||
const Nuxt = require('../../../')
|
const Nuxt = require('../../../')
|
||||||
const options = {
|
const options = {
|
||||||
rootDir: resolve(__dirname, '..')
|
rootDir: resolve(__dirname, '..'),
|
||||||
|
dev: false
|
||||||
}
|
}
|
||||||
return new Nuxt(options)
|
return new Nuxt(options)
|
||||||
.then(function (_nuxt) {
|
.then(function (_nuxt) {
|
||||||
@ -65,9 +65,11 @@ test('Route / exits and render HTML', async t => {
|
|||||||
*/
|
*/
|
||||||
test('Route / exits and render HTML', async t => {
|
test('Route / exits and render HTML', async t => {
|
||||||
const window = await renderAndGetWindow('/')
|
const window = await renderAndGetWindow('/')
|
||||||
t.is(window.document.querySelector('p').textContent, 'Hello world!')
|
const element = window.document.querySelector('.red-color')
|
||||||
t.is(window.document.querySelector('p').className, 'red-color')
|
t.not(element, null)
|
||||||
t.true(window.document.querySelectorAll('style')[2].textContent.includes('.red-color {\n color: red;\n}'))
|
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
|
// Close server and ask nuxt to stop listening to file changes
|
||||||
|
@ -176,5 +176,5 @@ Promise.all(resolveComponents)
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.catch((err) => {
|
.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 { app, router<%= (store ? ', store' : '') %> } from './index'
|
||||||
import { getMatchedComponents, getContext } from './utils'
|
import { getMatchedComponents, getContext } from './utils'
|
||||||
|
|
||||||
const isDev = process.env.NODE_ENV !== 'production'
|
const isDev = <%= isDev %>
|
||||||
const _app = new Vue(app)
|
const _app = new Vue(app)
|
||||||
|
|
||||||
// This exported function will be called by `bundleRenderer`.
|
// This exported function will be called by `bundleRenderer`.
|
||||||
@ -54,7 +54,7 @@ export default context => {
|
|||||||
}))
|
}))
|
||||||
.then((res) => {
|
.then((res) => {
|
||||||
<% if (isDev) { %>
|
<% 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
|
// datas are the first row of each
|
||||||
context.nuxt.data = res.map((tab) => tab[0])
|
context.nuxt.data = res.map((tab) => tab[0])
|
||||||
|
@ -42,21 +42,25 @@ const defaultsLoaders = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
module.exports = function * () {
|
module.exports = function * () {
|
||||||
if (this.options.build === false) {
|
const noBuild = this.options.build === false
|
||||||
return Promise.resolve()
|
|
||||||
}
|
|
||||||
// Defaults build options
|
// Defaults build options
|
||||||
if (this.options.build && Array.isArray(this.options.build.loaders)) {
|
if (this.options.build && Array.isArray(this.options.build.loaders)) {
|
||||||
this.options.build = _.defaultsDeep(this.options.build, defaults)
|
this.options.build = _.defaultsDeep(this.options.build, defaults)
|
||||||
} else {
|
} else {
|
||||||
this.options.build = _.defaultsDeep(this.options.build, defaults, { loaders: defaultsLoaders })
|
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
|
** Check if pages dir exists and warn if not
|
||||||
*/
|
*/
|
||||||
if (!fs.existsSync(join(this.dir, 'pages'))) {
|
if (!fs.existsSync(join(this.dir, 'pages'))) {
|
||||||
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 {
|
} else {
|
||||||
console.error('> Couldn\'t find a `pages` directory. Please create one under the project root')
|
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
|
** 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'))
|
yield mkdirp(r(this.dir, '.nuxt/components'))
|
||||||
if (this.isProd) {
|
if (!this.dev) {
|
||||||
yield mkdirp(r(this.dir, '.nuxt/dist'))
|
yield mkdirp(r(this.dir, '.nuxt/dist'))
|
||||||
}
|
}
|
||||||
/*
|
/*
|
||||||
@ -116,24 +122,24 @@ module.exports = function * () {
|
|||||||
'components/Loading.vue'
|
'components/Loading.vue'
|
||||||
]
|
]
|
||||||
let templateVars = {
|
let templateVars = {
|
||||||
isDev: this.isDev,
|
isDev: this.dev,
|
||||||
store: this.options.store,
|
store: this.options.store,
|
||||||
css: this.options.css,
|
css: this.options.css,
|
||||||
plugins: this.options.plugins.map((p) => r(this.dir, p)),
|
plugins: this.options.plugins.map((p) => r(this.dir, p)),
|
||||||
loading: (this.options.loading === 'string' ? r(this.dir, this.options.loading) : this.options.loading),
|
loading: (this.options.loading === 'string' ? r(this.dir, this.options.loading) : this.options.loading),
|
||||||
components: {
|
components: {
|
||||||
Loading: r(__dirname, '..', 'app', 'components', 'Loading.vue'),
|
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
|
routes: this.options.routes
|
||||||
}
|
}
|
||||||
if (this.options.store) {
|
if (this.options.store) {
|
||||||
templateVars.storePath = r(this.dir, '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')
|
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')
|
templateVars.components.ErrorPage = r(this.dir, 'pages/_error.vue')
|
||||||
}
|
}
|
||||||
const readFile = pify(fs.readFile)
|
const readFile = pify(fs.readFile)
|
||||||
@ -151,7 +157,7 @@ module.exports = function * () {
|
|||||||
/*
|
/*
|
||||||
** Generate .nuxt/dist/ files
|
** Generate .nuxt/dist/ files
|
||||||
*/
|
*/
|
||||||
if (this.isDev) {
|
if (this.dev) {
|
||||||
debug('Adding webpack middlewares...')
|
debug('Adding webpack middlewares...')
|
||||||
createWebpackMiddlewares.call(this)
|
createWebpackMiddlewares.call(this)
|
||||||
webpackWatchAndUpdate.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 () {
|
function getWebpackClientConfig () {
|
||||||
var config = require(r(__dirname, 'webpack', 'client.config.js'))
|
const clientConfigPath = r(__dirname, 'webpack', 'client.config.js')
|
||||||
config = _.cloneDeep(config)
|
return require(clientConfigPath).call(this)
|
||||||
// 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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function getWebpackServerConfig () {
|
function getWebpackServerConfig () {
|
||||||
var config = require(r(__dirname, 'webpack', 'server.config.js'))
|
const configServerPath = r(__dirname, 'webpack', 'server.config.js')
|
||||||
config = _.cloneDeep(config)
|
return require(configServerPath).call(this)
|
||||||
// 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)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
function createWebpackMiddlewares () {
|
function createWebpackMiddlewares () {
|
||||||
@ -270,7 +224,7 @@ function webpackRunClient () {
|
|||||||
const serverCompiler = webpack(clientConfig)
|
const serverCompiler = webpack(clientConfig)
|
||||||
serverCompiler.run((err, stats) => {
|
serverCompiler.run((err, stats) => {
|
||||||
if (err) return reject(err)
|
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()
|
resolve()
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -282,7 +236,7 @@ function webpackRunServer () {
|
|||||||
const serverCompiler = webpack(serverConfig)
|
const serverCompiler = webpack(serverConfig)
|
||||||
serverCompiler.run((err, stats) => {
|
serverCompiler.run((err, stats) => {
|
||||||
if (err) return reject(err)
|
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)
|
const bundlePath = join(serverConfig.output.path, serverConfig.output.filename)
|
||||||
createRenderer.call(this, fs.readFileSync(bundlePath, 'utf8'))
|
createRenderer.call(this, fs.readFileSync(bundlePath, 'utf8'))
|
||||||
resolve()
|
resolve()
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
const vueLoaderConfig = require('./vue-loader.config')
|
const vueLoaderConfig = require('./vue-loader.config')
|
||||||
|
const { join } = require('path')
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
@ -8,29 +9,49 @@ const vueLoaderConfig = require('./vue-loader.config')
|
|||||||
| webpack config files
|
| webpack config files
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
module.exports = {
|
module.exports = function () {
|
||||||
devtool: 'source-map',
|
const nodeModulesDir = join(__dirname, '..', '..', '..', 'node_modules')
|
||||||
entry: {
|
let config = {
|
||||||
vendor: ['vue', 'vue-router', 'vue-meta', 'es6-promise', 'es6-object-assign']
|
devtool: 'source-map',
|
||||||
},
|
entry: {
|
||||||
output: {
|
vendor: ['vue', 'vue-router', 'vue-meta', 'es6-promise', 'es6-object-assign']
|
||||||
publicPath: '/_nuxt/'
|
},
|
||||||
},
|
output: {
|
||||||
module: {
|
publicPath: '/_nuxt/'
|
||||||
rules: [
|
},
|
||||||
{
|
resolve: {
|
||||||
test: /\.vue$/,
|
modules: [
|
||||||
loader: 'vue',
|
nodeModulesDir,
|
||||||
options: vueLoaderConfig
|
join(this.dir, 'node_modules')
|
||||||
},
|
]
|
||||||
{
|
},
|
||||||
test: /\.js$/,
|
resolveLoader: {
|
||||||
loader: 'babel',
|
modules: [
|
||||||
exclude: /node_modules/,
|
nodeModulesDir,
|
||||||
options: {
|
join(this.dir, 'node_modules')
|
||||||
presets: ['es2015', 'stage-2']
|
]
|
||||||
|
},
|
||||||
|
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 webpack = require('webpack')
|
||||||
|
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
||||||
const base = require('./base.config')
|
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
|
| In production, will generate public/dist/style.css
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
|
module.exports = function () {
|
||||||
|
let config = base.call(this)
|
||||||
|
|
||||||
const config = Object.assign({}, base, {
|
// Entry
|
||||||
plugins: (base.plugins || []).concat([
|
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
|
// strip comments in Vue code
|
||||||
new webpack.DefinePlugin({
|
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
|
'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') {
|
// Production client build
|
||||||
// Use ExtractTextPlugin to extract CSS into a single file
|
if (!this.dev) {
|
||||||
// so it's applied on initial render
|
config.plugins.push(
|
||||||
const ExtractTextPlugin = require('extract-text-webpack-plugin')
|
// Use ExtractTextPlugin to extract CSS into a single file
|
||||||
|
new ExtractTextPlugin({
|
||||||
// vueConfig is already included in the config via LoaderOptionsPlugin
|
filename: this.options.build.filenames.css,
|
||||||
// here we overwrite the loader config for <style lang='stylus'>
|
allChunks: true
|
||||||
// so they are extracted.
|
}),
|
||||||
vueConfig.loaders.css = ExtractTextPlugin.extract({ loader: 'css-loader' })
|
// This is needed in webpack 2 for minifying CSS
|
||||||
vueConfig.loaders.scss = ExtractTextPlugin.extract({ loader: 'css-loader!sass-loader', fallbackLoader: 'vue-style-loader' })
|
new webpack.LoaderOptionsPlugin({
|
||||||
vueConfig.loaders.sass = ExtractTextPlugin.extract({ loader: 'css-loader!sass-loader?indentedSyntax', fallbackLoader: 'vue-style-loader' })
|
minimize: true
|
||||||
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' })
|
// Minify JS
|
||||||
|
new webpack.optimize.UglifyJsPlugin({
|
||||||
config.plugins.push(
|
compress: {
|
||||||
new ExtractTextPlugin({
|
warnings: false
|
||||||
filename: 'style.css',
|
}
|
||||||
allChunks: true
|
})
|
||||||
}),
|
)
|
||||||
// this is needed in webpack 2 for minifying CSS
|
}
|
||||||
new webpack.LoaderOptionsPlugin({
|
return config
|
||||||
minimize: true
|
|
||||||
}),
|
|
||||||
// minify JS
|
|
||||||
new webpack.optimize.UglifyJsPlugin({
|
|
||||||
compress: {
|
|
||||||
warnings: false
|
|
||||||
}
|
|
||||||
})
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = config
|
|
||||||
|
@ -1,23 +1,44 @@
|
|||||||
const webpack = require('webpack')
|
const webpack = require('webpack')
|
||||||
const base = require('./base.config')
|
const base = require('./base.config')
|
||||||
|
const { uniq } = require('lodash')
|
||||||
|
const { existsSync } = require('fs')
|
||||||
|
const { resolve } = require('path')
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
| Webpack Server Config
|
| Webpack Server Config
|
||||||
|--------------------------------------------------------------------------
|
|--------------------------------------------------------------------------
|
||||||
*/
|
*/
|
||||||
module.exports = Object.assign({}, base, {
|
module.exports = function () {
|
||||||
target: 'node',
|
let config = base.call(this)
|
||||||
devtool: false,
|
|
||||||
output: Object.assign({}, base.output, {
|
config = Object.assign(config, {
|
||||||
filename: 'server-bundle.js',
|
target: 'node',
|
||||||
libraryTarget: 'commonjs2'
|
devtool: false,
|
||||||
}),
|
entry: resolve(this.dir, '.nuxt', 'server.js'),
|
||||||
plugins: [
|
output: Object.assign({}, base.output, {
|
||||||
new webpack.DefinePlugin({
|
path: resolve(this.dir, '.nuxt', 'dist'),
|
||||||
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development'),
|
filename: 'server-bundle.js',
|
||||||
'process.env.VUE_ENV': '"server"',
|
libraryTarget: 'commonjs2'
|
||||||
'process.BROWSER': false
|
}),
|
||||||
})
|
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 = {
|
module.exports = function () {
|
||||||
postcss: [
|
let config = {
|
||||||
require('autoprefixer')({
|
postcss: [
|
||||||
browsers: ['last 3 versions']
|
require('autoprefixer')({
|
||||||
})
|
browsers: ['last 3 versions']
|
||||||
],
|
})
|
||||||
loaders: {
|
],
|
||||||
'js': 'babel-loader?presets[]=es2015&presets[]=stage-2',
|
loaders: {
|
||||||
'postcss': 'vue-style-loader!css-loader',
|
'js': 'babel-loader?presets[]=es2015&presets[]=stage-2',
|
||||||
'less': 'vue-style-loader!css-loader!less-loader',
|
'postcss': 'vue-style-loader!css-loader',
|
||||||
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax',
|
'less': 'vue-style-loader!css-loader!less-loader',
|
||||||
'scss': 'vue-style-loader!css-loader!sass-loader',
|
'sass': 'vue-style-loader!css-loader!sass-loader?indentedSyntax',
|
||||||
'stylus': 'vue-style-loader!css-loader!stylus-loader',
|
'scss': 'vue-style-loader!css-loader!sass-loader',
|
||||||
'styl': 'vue-style-loader!css-loader!stylus-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) {
|
constructor (options = {}, cb) {
|
||||||
var defaults = {
|
var defaults = {
|
||||||
|
dev: true,
|
||||||
routes: [],
|
routes: [],
|
||||||
plugins: [],
|
plugins: [],
|
||||||
css: [],
|
css: [],
|
||||||
@ -32,8 +33,7 @@ class Nuxt {
|
|||||||
if (options.loading === true) delete options.loading
|
if (options.loading === true) delete options.loading
|
||||||
this.options = _.defaultsDeep(options, defaults)
|
this.options = _.defaultsDeep(options, defaults)
|
||||||
// Env variables
|
// Env variables
|
||||||
this.isProd = process.env.NODE_ENV === 'production'
|
this.dev = this.options.dev
|
||||||
this.isDev = !process.env.NODE_ENV || process.env.NODE_ENV === 'development'
|
|
||||||
this.dir = (typeof options.rootDir === 'string' && options.rootDir ? options.rootDir : process.cwd())
|
this.dir = (typeof options.rootDir === 'string' && options.rootDir ? options.rootDir : process.cwd())
|
||||||
// Template
|
// Template
|
||||||
this.appTemplate = _.template(fs.readFileSync(resolve(__dirname, 'views', 'app.html'), 'utf8'), {
|
this.appTemplate = _.template(fs.readFileSync(resolve(__dirname, 'views', 'app.html'), 'utf8'), {
|
||||||
@ -70,7 +70,7 @@ class Nuxt {
|
|||||||
const self = this
|
const self = this
|
||||||
const context = getContext(req, res)
|
const context = getContext(req, res)
|
||||||
co(function * () {
|
co(function * () {
|
||||||
if (self.isDev) {
|
if (self.dev) {
|
||||||
// Call webpack middlewares only in development
|
// Call webpack middlewares only in development
|
||||||
yield self.webpackDevMiddleware(req, res)
|
yield self.webpackDevMiddleware(req, res)
|
||||||
yield self.webpackHotMiddleware(req, res)
|
yield self.webpackHotMiddleware(req, res)
|
||||||
@ -84,7 +84,7 @@ class Nuxt {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
.then(() => {
|
.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
|
res.statusCode = 404
|
||||||
return res.end()
|
return res.end()
|
||||||
}
|
}
|
||||||
@ -115,7 +115,7 @@ class Nuxt {
|
|||||||
context.nuxt.error = { statusCode: 500, message: context.nuxt.error.message }
|
context.nuxt.error = { statusCode: 500, message: context.nuxt.error.message }
|
||||||
}
|
}
|
||||||
const app = self.appTemplate({
|
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,
|
APP: html,
|
||||||
context: context,
|
context: context,
|
||||||
files: {
|
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>
|
<html>
|
||||||
<head>
|
<head>
|
||||||
${title.toString()}
|
${title.toString()}
|
||||||
<% if (isProd) { %><link rel="stylesheet" href="<%= files.css %>"><% } %>
|
<% if (!dev) { %><link rel="stylesheet" href="<%= files.css %>"><% } %>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<%= APP %>
|
<%= APP %>
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "nuxt",
|
"name": "nuxt",
|
||||||
"version": "0.2.5",
|
"version": "0.2.6",
|
||||||
"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)",
|
||||||
"main": "index.js",
|
"main": "index.js",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
|
@ -25,7 +25,7 @@ test(async t => {
|
|||||||
|
|
||||||
test(async t => {
|
test(async t => {
|
||||||
const html = await (render('/head'))
|
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>'))
|
t.true(html.includes('<div><h1>I can haz meta tags</h1></div>'))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user