mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-11 16:43:55 +00:00
Merge pull request #2748 from ricardogobbosouza/config-pages-dir
feat: custom directories
This commit is contained in:
commit
72300d350e
@ -1,5 +1,5 @@
|
||||
<% if (middleware) { %>
|
||||
let files = require.context('@/middleware', false, /^\.\/(?!<%= ignorePrefix %>).*\.(<%= extensions %>)$/)
|
||||
let files = require.context('@/<%= dir.middleware %>', false, /^\.\/(?!<%= ignorePrefix %>).*\.(<%= extensions %>)$/)
|
||||
let filenames = files.keys()
|
||||
|
||||
function getModule (filename) {
|
||||
|
@ -3,14 +3,14 @@ import Vuex from 'vuex'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
// Recursive find files in {srcDir}/store
|
||||
const files = require.context('@/store', true, /^\.\/(?!<%= ignorePrefix %>).*\.(<%= extensions %>)$/)
|
||||
// Recursive find files in {srcDir}/{dir.store}
|
||||
const files = require.context('@/<%= dir.store %>', true, /^\.\/(?!<%= ignorePrefix %>).*\.(<%= extensions %>)$/)
|
||||
const filenames = files.keys()
|
||||
|
||||
// Store
|
||||
let storeData = {}
|
||||
|
||||
// Check if store/index.js exists
|
||||
// Check if {dir.store}/index.js exists
|
||||
let indexFilename
|
||||
filenames.forEach((filename) => {
|
||||
if (filename.indexOf('./index.') !== -1) {
|
||||
@ -57,10 +57,10 @@ function getModule (filename) {
|
||||
const file = files(filename)
|
||||
const module = file.default || file
|
||||
if (module.commit) {
|
||||
throw new Error('[nuxt] store/' + filename.replace('./', '') + ' should export a method which returns a Vuex instance.')
|
||||
throw new Error('[nuxt] <%= dir.store %>/' + filename.replace('./', '') + ' should export a method which returns a Vuex instance.')
|
||||
}
|
||||
if (module.state && typeof module.state !== 'function') {
|
||||
throw new Error('[nuxt] state should be a function in store/' + filename.replace('./', ''))
|
||||
throw new Error('[nuxt] state should be a function in <%= dir.store %>/' + filename.replace('./', ''))
|
||||
}
|
||||
return module
|
||||
}
|
||||
|
@ -137,15 +137,15 @@ module.exports = class Builder {
|
||||
// Check if pages dir exists and warn if not
|
||||
this._nuxtPages = typeof this.options.build.createRoutes !== 'function'
|
||||
if (this._nuxtPages) {
|
||||
if (!existsSync(join(this.options.srcDir, 'pages'))) {
|
||||
if (!existsSync(join(this.options.srcDir, this.options.dir.pages))) {
|
||||
let dir = this.options.srcDir
|
||||
if (existsSync(join(this.options.srcDir, '..', 'pages'))) {
|
||||
if (existsSync(join(this.options.srcDir, '..', this.options.dir.pages))) {
|
||||
throw new Error(
|
||||
`No \`pages\` directory found in ${dir}. Did you mean to run \`nuxt\` in the parent (\`../\`) directory?`
|
||||
`No \`${this.options.dir.pages}\` directory found in ${dir}. Did you mean to run \`nuxt\` in the parent (\`../\`) directory?`
|
||||
)
|
||||
} else {
|
||||
throw new Error(
|
||||
`Couldn't find a \`pages\` directory in ${dir}. Please create one under the project root`
|
||||
`Couldn't find a \`${this.options.dir.pages}\` directory in ${dir}. Please create one under the project root`
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -250,7 +250,7 @@ module.exports = class Builder {
|
||||
router: this.options.router,
|
||||
env: this.options.env,
|
||||
head: this.options.head,
|
||||
middleware: existsSync(join(this.options.srcDir, 'middleware')),
|
||||
middleware: existsSync(join(this.options.srcDir, this.options.dir.middleware)),
|
||||
store: this.options.store,
|
||||
css: this.options.css,
|
||||
plugins: this.plugins,
|
||||
@ -263,6 +263,7 @@ module.exports = class Builder {
|
||||
: this.options.loading,
|
||||
transition: this.options.transition,
|
||||
layoutTransition: this.options.layoutTransition,
|
||||
dir: this.options.dir,
|
||||
components: {
|
||||
ErrorPage: this.options.ErrorPage
|
||||
? this.relativeToBuild(this.options.ErrorPage)
|
||||
@ -271,8 +272,8 @@ module.exports = class Builder {
|
||||
}
|
||||
|
||||
// -- Layouts --
|
||||
if (existsSync(resolve(this.options.srcDir, 'layouts'))) {
|
||||
const layoutsFiles = await glob('layouts/**/*.{vue,js}', {
|
||||
if (existsSync(resolve(this.options.srcDir, this.options.dir.layouts))) {
|
||||
const layoutsFiles = await glob(`${this.options.dir.layouts}/**/*.{vue,js}`, {
|
||||
cwd: this.options.srcDir,
|
||||
ignore: this.options.ignore
|
||||
})
|
||||
@ -297,7 +298,7 @@ module.exports = class Builder {
|
||||
if (!templateVars.components.ErrorPage && hasErrorLayout) {
|
||||
templateVars.components.ErrorPage = this.relativeToBuild(
|
||||
this.options.srcDir,
|
||||
'layouts/error.vue'
|
||||
`${this.options.dir.layouts}/error.vue`
|
||||
)
|
||||
}
|
||||
}
|
||||
@ -314,7 +315,7 @@ module.exports = class Builder {
|
||||
if (this._nuxtPages) {
|
||||
// Use nuxt.js createRoutes bases on pages/
|
||||
const files = {}
|
||||
;(await glob('pages/**/*.{vue,js}', {
|
||||
;(await glob(`${this.options.dir.pages}/**/*.{vue,js}`, {
|
||||
cwd: this.options.srcDir,
|
||||
ignore: this.options.ignore
|
||||
})).forEach(f => {
|
||||
@ -325,7 +326,8 @@ module.exports = class Builder {
|
||||
})
|
||||
templateVars.router.routes = createRoutes(
|
||||
Object.values(files),
|
||||
this.options.srcDir
|
||||
this.options.srcDir,
|
||||
this.options.dir.pages
|
||||
)
|
||||
} else {
|
||||
templateVars.router.routes = this.options.build.createRoutes(
|
||||
@ -638,17 +640,17 @@ module.exports = class Builder {
|
||||
watchFiles() {
|
||||
const src = this.options.srcDir
|
||||
let patterns = [
|
||||
r(src, 'layouts'),
|
||||
r(src, 'store'),
|
||||
r(src, 'middleware'),
|
||||
r(src, 'layouts/*.{vue,js}'),
|
||||
r(src, 'layouts/**/*.{vue,js}')
|
||||
r(src, this.options.dir.layouts),
|
||||
r(src, this.options.dir.store),
|
||||
r(src, this.options.dir.middleware),
|
||||
r(src, `${this.options.dir.layouts}/*.{vue,js}`),
|
||||
r(src, `${this.options.dir.layouts}/**/*.{vue,js}`)
|
||||
]
|
||||
if (this._nuxtPages) {
|
||||
patterns.push(
|
||||
r(src, 'pages'),
|
||||
r(src, 'pages/*.{vue,js}'),
|
||||
r(src, 'pages/**/*.{vue,js}')
|
||||
r(src, this.options.dir.pages),
|
||||
r(src, `${this.options.dir.pages}/*.{vue,js}`),
|
||||
r(src, `${this.options.dir.pages}/**/*.{vue,js}`)
|
||||
)
|
||||
}
|
||||
patterns = _.map(patterns, p => upath.normalizeSafe(p))
|
||||
|
@ -27,7 +27,7 @@ module.exports = class Generator {
|
||||
this.builder = builder
|
||||
|
||||
// Set variables
|
||||
this.staticRoutes = resolve(this.options.srcDir, 'static')
|
||||
this.staticRoutes = resolve(this.options.srcDir, this.options.dir.static)
|
||||
this.srcBuiltPath = resolve(this.options.buildDir, 'dist')
|
||||
this.distPath = resolve(this.options.rootDir, this.options.generate.dir)
|
||||
this.distNuxtPath = join(
|
||||
|
@ -19,6 +19,13 @@ module.exports = function webpackBaseConfig({ name, isServer }) {
|
||||
// Prioritize nested node_modules in webpack search path (#2558)
|
||||
const webpackModulesDir = ['node_modules'].concat(this.options.modulesDir)
|
||||
|
||||
const configAlias = {}
|
||||
|
||||
// Used by vue-loader so we can use in templates
|
||||
// with <img src="~/assets/nuxt.png"/>
|
||||
configAlias[this.options.dir.assets] = join(this.options.srcDir, this.options.dir.assets)
|
||||
configAlias[this.options.dir.static] = join(this.options.srcDir, this.options.dir.static)
|
||||
|
||||
const config = {
|
||||
name,
|
||||
entry: {
|
||||
@ -39,16 +46,12 @@ module.exports = function webpackBaseConfig({ name, isServer }) {
|
||||
},
|
||||
resolve: {
|
||||
extensions: ['.js', '.json', '.vue', '.jsx'],
|
||||
alias: {
|
||||
alias: Object.assign({
|
||||
'~': join(this.options.srcDir),
|
||||
'~~': join(this.options.rootDir),
|
||||
'@': join(this.options.srcDir),
|
||||
'@@': join(this.options.rootDir),
|
||||
// Used by vue-loader so we can use in templates
|
||||
// with <img src="~/assets/nuxt.png"/>
|
||||
assets: join(this.options.srcDir, 'assets'),
|
||||
static: join(this.options.srcDir, 'static')
|
||||
},
|
||||
'@@': join(this.options.rootDir)
|
||||
}, configAlias),
|
||||
modules: webpackModulesDir
|
||||
},
|
||||
resolveLoader: {
|
||||
|
@ -56,16 +56,17 @@ module.exports = function styleLoader(ext, loaders = [], isVueLoader = false) {
|
||||
|
||||
// css-loader
|
||||
// https://github.com/webpack-contrib/css-loader
|
||||
const cssLoaderAlias = {}
|
||||
cssLoaderAlias[`/${this.options.dir.assets}`] = join(this.options.srcDir, this.options.dir.assets)
|
||||
cssLoaderAlias[`/${this.options.dir.static}`] = join(this.options.srcDir, this.options.dir.static)
|
||||
|
||||
loaders.unshift({
|
||||
loader: 'css-loader',
|
||||
options: {
|
||||
sourceMap,
|
||||
minimize: !this.options.dev,
|
||||
importLoaders: loaders.length, // Important!
|
||||
alias: {
|
||||
'/static': join(this.options.srcDir, 'static'),
|
||||
'/assets': join(this.options.srcDir, 'assets')
|
||||
}
|
||||
alias: cssLoaderAlias
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -85,7 +85,7 @@ Options.from = function (_options) {
|
||||
}
|
||||
|
||||
// If store defined, update store options to true unless explicitly disabled
|
||||
if (options.store !== false && existsSync(join(options.srcDir, 'store'))) {
|
||||
if (options.store !== false && existsSync(join(options.srcDir, options.dir.store))) {
|
||||
options.store = true
|
||||
}
|
||||
|
||||
@ -284,6 +284,14 @@ Options.defaults = {
|
||||
name: 'layout',
|
||||
mode: 'out-in'
|
||||
},
|
||||
dir: {
|
||||
assets: 'assets',
|
||||
layouts: 'layouts',
|
||||
middleware: 'middleware',
|
||||
pages: 'pages',
|
||||
static: 'static',
|
||||
store: 'store'
|
||||
},
|
||||
router: {
|
||||
mode: 'history',
|
||||
base: '/',
|
||||
|
@ -254,11 +254,11 @@ function cleanChildrenRoutes(routes, isChild = false) {
|
||||
return routes
|
||||
}
|
||||
|
||||
exports.createRoutes = function createRoutes(files, srcDir) {
|
||||
exports.createRoutes = function createRoutes(files, srcDir, pagesDir) {
|
||||
let routes = []
|
||||
files.forEach(file => {
|
||||
let keys = file
|
||||
.replace(/^pages/, '')
|
||||
.replace(RegExp(`^${pagesDir}`), '')
|
||||
.replace(/\.(vue|js)$/, '')
|
||||
.replace(/\/{2,}/g, '/')
|
||||
.split('/')
|
||||
|
@ -250,7 +250,7 @@ module.exports = class Renderer {
|
||||
|
||||
// For serving static/ files to /
|
||||
const staticMiddleware = serveStatic(
|
||||
resolve(this.options.srcDir, 'static'),
|
||||
resolve(this.options.srcDir, this.options.dir.static),
|
||||
this.options.render.static
|
||||
)
|
||||
staticMiddleware.prefix = this.options.render.static.prefix
|
||||
|
62
test/custom-dirs.test.js
Normal file
62
test/custom-dirs.test.js
Normal file
@ -0,0 +1,62 @@
|
||||
import test from 'ava'
|
||||
import { resolve } from 'path'
|
||||
import rp from 'request-promise-native'
|
||||
import { Nuxt, Builder } from '..'
|
||||
import { interceptLog } from './helpers/console'
|
||||
|
||||
const port = 4007
|
||||
const url = route => 'http://localhost:' + port + route
|
||||
|
||||
let nuxt = null
|
||||
let builder = null
|
||||
|
||||
// Init nuxt.js and create server listening on localhost:4000
|
||||
test.before('Init Nuxt.js', async t => {
|
||||
const rootDir = resolve(__dirname, 'fixtures/custom-dirs')
|
||||
let config = require(resolve(rootDir, 'nuxt.config.js'))
|
||||
config.rootDir = rootDir
|
||||
config.dev = false
|
||||
|
||||
const logSpy = await interceptLog(async () => {
|
||||
nuxt = new Nuxt(config)
|
||||
builder = new Builder(nuxt)
|
||||
await builder.build()
|
||||
await nuxt.listen(4007, 'localhost')
|
||||
})
|
||||
|
||||
t.true(logSpy.calledWithMatch('DONE'))
|
||||
t.true(logSpy.calledWithMatch('OPEN'))
|
||||
})
|
||||
|
||||
test('custom assets directory', async t => {
|
||||
const { html } = await nuxt.renderRoute('/')
|
||||
t.true(html.includes('.global-css-selector'))
|
||||
})
|
||||
|
||||
test('custom layouts directory', async t => {
|
||||
const { html } = await nuxt.renderRoute('/')
|
||||
t.true(html.includes('<p>I have custom layouts directory</p>'))
|
||||
})
|
||||
|
||||
test('custom middleware directory', async t => {
|
||||
const window = await nuxt.renderAndGetWindow(url('/user-agent'))
|
||||
const html = window.document.body.innerHTML
|
||||
t.true(html.includes('<pre>Mozilla'))
|
||||
})
|
||||
|
||||
test('custom pages directory', async t => {
|
||||
const { html } = await nuxt.renderRoute('/')
|
||||
t.true(html.includes('<h1>I have custom pages directory</h1>'))
|
||||
})
|
||||
|
||||
test('custom static directory', async t => {
|
||||
const { headers } = await rp(url('/test.txt'), {
|
||||
resolveWithFullResponse: true
|
||||
})
|
||||
t.is(headers['cache-control'], 'public, max-age=0')
|
||||
})
|
||||
|
||||
// Close server and ask nuxt to stop listening to file changes
|
||||
test.after.always('Closing server and nuxt.js', async t => {
|
||||
await nuxt.close()
|
||||
})
|
3
test/fixtures/custom-dirs/custom-assets/app.css
vendored
Normal file
3
test/fixtures/custom-dirs/custom-assets/app.css
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.global-css-selector {
|
||||
color: red;
|
||||
}
|
6
test/fixtures/custom-dirs/custom-layouts/default.vue
vendored
Normal file
6
test/fixtures/custom-dirs/custom-layouts/default.vue
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
<template>
|
||||
<div>
|
||||
<nuxt/>
|
||||
<p>I have custom layouts directory</p>
|
||||
</div>
|
||||
</template>
|
3
test/fixtures/custom-dirs/custom-middleware/user-agent.js
vendored
Normal file
3
test/fixtures/custom-dirs/custom-middleware/user-agent.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
export default function (context) {
|
||||
context.userAgent = process.server ? context.req.headers['user-agent'] : navigator.userAgent
|
||||
}
|
5
test/fixtures/custom-dirs/custom-pages/index.vue
vendored
Normal file
5
test/fixtures/custom-dirs/custom-pages/index.vue
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<div>
|
||||
<h1>I have custom pages directory</h1>
|
||||
</div>
|
||||
</template>
|
12
test/fixtures/custom-dirs/custom-pages/user-agent.vue
vendored
Normal file
12
test/fixtures/custom-dirs/custom-pages/user-agent.vue
vendored
Normal file
@ -0,0 +1,12 @@
|
||||
<template>
|
||||
<pre>{{ userAgent }}</pre>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
middleware: 'user-agent',
|
||||
asyncData({ userAgent }) {
|
||||
return { userAgent }
|
||||
}
|
||||
}
|
||||
</script>
|
1
test/fixtures/custom-dirs/custom-static/test.txt
vendored
Normal file
1
test/fixtures/custom-dirs/custom-static/test.txt
vendored
Normal file
@ -0,0 +1 @@
|
||||
A test here :)
|
17
test/fixtures/custom-dirs/custom-store/index.js
vendored
Normal file
17
test/fixtures/custom-dirs/custom-store/index.js
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
import Vue from 'vue'
|
||||
import Vuex from 'vuex'
|
||||
|
||||
Vue.use(Vuex)
|
||||
|
||||
const store = () => new Vuex.Store({
|
||||
state: {
|
||||
counter: 0
|
||||
},
|
||||
mutations: {
|
||||
increment(state) {
|
||||
state.counter++
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export default store
|
11
test/fixtures/custom-dirs/nuxt.config.js
vendored
Normal file
11
test/fixtures/custom-dirs/nuxt.config.js
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
module.exports = {
|
||||
css: [{ src: '~/custom-assets/app.css' }],
|
||||
dir: {
|
||||
assets: 'custom-assets',
|
||||
layouts: 'custom-layouts',
|
||||
middleware: 'custom-middleware',
|
||||
pages: 'custom-pages',
|
||||
static: 'custom-static',
|
||||
store: 'custom-store'
|
||||
}
|
||||
}
|
5
test/fixtures/custom-dirs/package.json
vendored
Normal file
5
test/fixtures/custom-dirs/package.json
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
{
|
||||
"name": "custom-dirs",
|
||||
"version": "1.0.0",
|
||||
"dependencies": {}
|
||||
}
|
Loading…
Reference in New Issue
Block a user