Skip to content

Commit 72300d3

Browse files
authored
Merge pull request nuxt#2748 from ricardogobbosouza/config-pages-dir
feat: custom directories
2 parents c959899 + a6200a2 commit 72300d3

File tree

19 files changed

+179
-40
lines changed

19 files changed

+179
-40
lines changed

lib/app/middleware.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<% if (middleware) { %>
2-
let files = require.context('@/middleware', false, /^\.\/(?!<%= ignorePrefix %>).*\.(<%= extensions %>)$/)
2+
let files = require.context('@/<%= dir.middleware %>', false, /^\.\/(?!<%= ignorePrefix %>).*\.(<%= extensions %>)$/)
33
let filenames = files.keys()
44

55
function getModule (filename) {

lib/app/store.js

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,14 @@ import Vuex from 'vuex'
33

44
Vue.use(Vuex)
55

6-
// Recursive find files in {srcDir}/store
7-
const files = require.context('@/store', true, /^\.\/(?!<%= ignorePrefix %>).*\.(<%= extensions %>)$/)
6+
// Recursive find files in {srcDir}/{dir.store}
7+
const files = require.context('@/<%= dir.store %>', true, /^\.\/(?!<%= ignorePrefix %>).*\.(<%= extensions %>)$/)
88
const filenames = files.keys()
99

1010
// Store
1111
let storeData = {}
1212

13-
// Check if store/index.js exists
13+
// Check if {dir.store}/index.js exists
1414
let indexFilename
1515
filenames.forEach((filename) => {
1616
if (filename.indexOf('./index.') !== -1) {
@@ -57,10 +57,10 @@ function getModule (filename) {
5757
const file = files(filename)
5858
const module = file.default || file
5959
if (module.commit) {
60-
throw new Error('[nuxt] store/' + filename.replace('./', '') + ' should export a method which returns a Vuex instance.')
60+
throw new Error('[nuxt] <%= dir.store %>/' + filename.replace('./', '') + ' should export a method which returns a Vuex instance.')
6161
}
6262
if (module.state && typeof module.state !== 'function') {
63-
throw new Error('[nuxt] state should be a function in store/' + filename.replace('./', ''))
63+
throw new Error('[nuxt] state should be a function in <%= dir.store %>/' + filename.replace('./', ''))
6464
}
6565
return module
6666
}

lib/builder/builder.js

Lines changed: 20 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -137,15 +137,15 @@ module.exports = class Builder {
137137
// Check if pages dir exists and warn if not
138138
this._nuxtPages = typeof this.options.build.createRoutes !== 'function'
139139
if (this._nuxtPages) {
140-
if (!existsSync(join(this.options.srcDir, 'pages'))) {
140+
if (!existsSync(join(this.options.srcDir, this.options.dir.pages))) {
141141
let dir = this.options.srcDir
142-
if (existsSync(join(this.options.srcDir, '..', 'pages'))) {
142+
if (existsSync(join(this.options.srcDir, '..', this.options.dir.pages))) {
143143
throw new Error(
144-
`No \`pages\` directory found in ${dir}. Did you mean to run \`nuxt\` in the parent (\`../\`) directory?`
144+
`No \`${this.options.dir.pages}\` directory found in ${dir}. Did you mean to run \`nuxt\` in the parent (\`../\`) directory?`
145145
)
146146
} else {
147147
throw new Error(
148-
`Couldn't find a \`pages\` directory in ${dir}. Please create one under the project root`
148+
`Couldn't find a \`${this.options.dir.pages}\` directory in ${dir}. Please create one under the project root`
149149
)
150150
}
151151
}
@@ -250,7 +250,7 @@ module.exports = class Builder {
250250
router: this.options.router,
251251
env: this.options.env,
252252
head: this.options.head,
253-
middleware: existsSync(join(this.options.srcDir, 'middleware')),
253+
middleware: existsSync(join(this.options.srcDir, this.options.dir.middleware)),
254254
store: this.options.store,
255255
css: this.options.css,
256256
plugins: this.plugins,
@@ -263,6 +263,7 @@ module.exports = class Builder {
263263
: this.options.loading,
264264
transition: this.options.transition,
265265
layoutTransition: this.options.layoutTransition,
266+
dir: this.options.dir,
266267
components: {
267268
ErrorPage: this.options.ErrorPage
268269
? this.relativeToBuild(this.options.ErrorPage)
@@ -271,8 +272,8 @@ module.exports = class Builder {
271272
}
272273

273274
// -- Layouts --
274-
if (existsSync(resolve(this.options.srcDir, 'layouts'))) {
275-
const layoutsFiles = await glob('layouts/**/*.{vue,js}', {
275+
if (existsSync(resolve(this.options.srcDir, this.options.dir.layouts))) {
276+
const layoutsFiles = await glob(`${this.options.dir.layouts}/**/*.{vue,js}`, {
276277
cwd: this.options.srcDir,
277278
ignore: this.options.ignore
278279
})
@@ -297,7 +298,7 @@ module.exports = class Builder {
297298
if (!templateVars.components.ErrorPage && hasErrorLayout) {
298299
templateVars.components.ErrorPage = this.relativeToBuild(
299300
this.options.srcDir,
300-
'layouts/error.vue'
301+
`${this.options.dir.layouts}/error.vue`
301302
)
302303
}
303304
}
@@ -314,7 +315,7 @@ module.exports = class Builder {
314315
if (this._nuxtPages) {
315316
// Use nuxt.js createRoutes bases on pages/
316317
const files = {}
317-
;(await glob('pages/**/*.{vue,js}', {
318+
;(await glob(`${this.options.dir.pages}/**/*.{vue,js}`, {
318319
cwd: this.options.srcDir,
319320
ignore: this.options.ignore
320321
})).forEach(f => {
@@ -325,7 +326,8 @@ module.exports = class Builder {
325326
})
326327
templateVars.router.routes = createRoutes(
327328
Object.values(files),
328-
this.options.srcDir
329+
this.options.srcDir,
330+
this.options.dir.pages
329331
)
330332
} else {
331333
templateVars.router.routes = this.options.build.createRoutes(
@@ -638,17 +640,17 @@ module.exports = class Builder {
638640
watchFiles() {
639641
const src = this.options.srcDir
640642
let patterns = [
641-
r(src, 'layouts'),
642-
r(src, 'store'),
643-
r(src, 'middleware'),
644-
r(src, 'layouts/*.{vue,js}'),
645-
r(src, 'layouts/**/*.{vue,js}')
643+
r(src, this.options.dir.layouts),
644+
r(src, this.options.dir.store),
645+
r(src, this.options.dir.middleware),
646+
r(src, `${this.options.dir.layouts}/*.{vue,js}`),
647+
r(src, `${this.options.dir.layouts}/**/*.{vue,js}`)
646648
]
647649
if (this._nuxtPages) {
648650
patterns.push(
649-
r(src, 'pages'),
650-
r(src, 'pages/*.{vue,js}'),
651-
r(src, 'pages/**/*.{vue,js}')
651+
r(src, this.options.dir.pages),
652+
r(src, `${this.options.dir.pages}/*.{vue,js}`),
653+
r(src, `${this.options.dir.pages}/**/*.{vue,js}`)
652654
)
653655
}
654656
patterns = _.map(patterns, p => upath.normalizeSafe(p))

lib/builder/generator.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ module.exports = class Generator {
2727
this.builder = builder
2828

2929
// Set variables
30-
this.staticRoutes = resolve(this.options.srcDir, 'static')
30+
this.staticRoutes = resolve(this.options.srcDir, this.options.dir.static)
3131
this.srcBuiltPath = resolve(this.options.buildDir, 'dist')
3232
this.distPath = resolve(this.options.rootDir, this.options.generate.dir)
3333
this.distNuxtPath = join(

lib/builder/webpack/base.config.js

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ module.exports = function webpackBaseConfig({ name, isServer }) {
1919
// Prioritize nested node_modules in webpack search path (#2558)
2020
const webpackModulesDir = ['node_modules'].concat(this.options.modulesDir)
2121

22+
const configAlias = {}
23+
24+
// Used by vue-loader so we can use in templates
25+
// with <img src="~/assets/nuxt.png"/>
26+
configAlias[this.options.dir.assets] = join(this.options.srcDir, this.options.dir.assets)
27+
configAlias[this.options.dir.static] = join(this.options.srcDir, this.options.dir.static)
28+
2229
const config = {
2330
name,
2431
entry: {
@@ -39,16 +46,12 @@ module.exports = function webpackBaseConfig({ name, isServer }) {
3946
},
4047
resolve: {
4148
extensions: ['.js', '.json', '.vue', '.jsx'],
42-
alias: {
49+
alias: Object.assign({
4350
'~': join(this.options.srcDir),
4451
'~~': join(this.options.rootDir),
4552
'@': join(this.options.srcDir),
46-
'@@': join(this.options.rootDir),
47-
// Used by vue-loader so we can use in templates
48-
// with <img src="~/assets/nuxt.png"/>
49-
assets: join(this.options.srcDir, 'assets'),
50-
static: join(this.options.srcDir, 'static')
51-
},
53+
'@@': join(this.options.rootDir)
54+
}, configAlias),
5255
modules: webpackModulesDir
5356
},
5457
resolveLoader: {

lib/builder/webpack/style-loader.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -56,16 +56,17 @@ module.exports = function styleLoader(ext, loaders = [], isVueLoader = false) {
5656

5757
// css-loader
5858
// https://github.com/webpack-contrib/css-loader
59+
const cssLoaderAlias = {}
60+
cssLoaderAlias[`/${this.options.dir.assets}`] = join(this.options.srcDir, this.options.dir.assets)
61+
cssLoaderAlias[`/${this.options.dir.static}`] = join(this.options.srcDir, this.options.dir.static)
62+
5963
loaders.unshift({
6064
loader: 'css-loader',
6165
options: {
6266
sourceMap,
6367
minimize: !this.options.dev,
6468
importLoaders: loaders.length, // Important!
65-
alias: {
66-
'/static': join(this.options.srcDir, 'static'),
67-
'/assets': join(this.options.srcDir, 'assets')
68-
}
69+
alias: cssLoaderAlias
6970
}
7071
})
7172

lib/common/options.js

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ Options.from = function (_options) {
8585
}
8686

8787
// If store defined, update store options to true unless explicitly disabled
88-
if (options.store !== false && existsSync(join(options.srcDir, 'store'))) {
88+
if (options.store !== false && existsSync(join(options.srcDir, options.dir.store))) {
8989
options.store = true
9090
}
9191

@@ -284,6 +284,14 @@ Options.defaults = {
284284
name: 'layout',
285285
mode: 'out-in'
286286
},
287+
dir: {
288+
assets: 'assets',
289+
layouts: 'layouts',
290+
middleware: 'middleware',
291+
pages: 'pages',
292+
static: 'static',
293+
store: 'store'
294+
},
287295
router: {
288296
mode: 'history',
289297
base: '/',

lib/common/utils.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -254,11 +254,11 @@ function cleanChildrenRoutes(routes, isChild = false) {
254254
return routes
255255
}
256256

257-
exports.createRoutes = function createRoutes(files, srcDir) {
257+
exports.createRoutes = function createRoutes(files, srcDir, pagesDir) {
258258
let routes = []
259259
files.forEach(file => {
260260
let keys = file
261-
.replace(/^pages/, '')
261+
.replace(RegExp(`^${pagesDir}`), '')
262262
.replace(/\.(vue|js)$/, '')
263263
.replace(/\/{2,}/g, '/')
264264
.split('/')

lib/core/renderer.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -250,7 +250,7 @@ module.exports = class Renderer {
250250

251251
// For serving static/ files to /
252252
const staticMiddleware = serveStatic(
253-
resolve(this.options.srcDir, 'static'),
253+
resolve(this.options.srcDir, this.options.dir.static),
254254
this.options.render.static
255255
)
256256
staticMiddleware.prefix = this.options.render.static.prefix

test/custom-dirs.test.js

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import test from 'ava'
2+
import { resolve } from 'path'
3+
import rp from 'request-promise-native'
4+
import { Nuxt, Builder } from '..'
5+
import { interceptLog } from './helpers/console'
6+
7+
const port = 4007
8+
const url = route => 'http://localhost:' + port + route
9+
10+
let nuxt = null
11+
let builder = null
12+
13+
// Init nuxt.js and create server listening on localhost:4000
14+
test.before('Init Nuxt.js', async t => {
15+
const rootDir = resolve(__dirname, 'fixtures/custom-dirs')
16+
let config = require(resolve(rootDir, 'nuxt.config.js'))
17+
config.rootDir = rootDir
18+
config.dev = false
19+
20+
const logSpy = await interceptLog(async () => {
21+
nuxt = new Nuxt(config)
22+
builder = new Builder(nuxt)
23+
await builder.build()
24+
await nuxt.listen(4007, 'localhost')
25+
})
26+
27+
t.true(logSpy.calledWithMatch('DONE'))
28+
t.true(logSpy.calledWithMatch('OPEN'))
29+
})
30+
31+
test('custom assets directory', async t => {
32+
const { html } = await nuxt.renderRoute('/')
33+
t.true(html.includes('.global-css-selector'))
34+
})
35+
36+
test('custom layouts directory', async t => {
37+
const { html } = await nuxt.renderRoute('/')
38+
t.true(html.includes('<p>I have custom layouts directory</p>'))
39+
})
40+
41+
test('custom middleware directory', async t => {
42+
const window = await nuxt.renderAndGetWindow(url('/user-agent'))
43+
const html = window.document.body.innerHTML
44+
t.true(html.includes('<pre>Mozilla'))
45+
})
46+
47+
test('custom pages directory', async t => {
48+
const { html } = await nuxt.renderRoute('/')
49+
t.true(html.includes('<h1>I have custom pages directory</h1>'))
50+
})
51+
52+
test('custom static directory', async t => {
53+
const { headers } = await rp(url('/test.txt'), {
54+
resolveWithFullResponse: true
55+
})
56+
t.is(headers['cache-control'], 'public, max-age=0')
57+
})
58+
59+
// Close server and ask nuxt to stop listening to file changes
60+
test.after.always('Closing server and nuxt.js', async t => {
61+
await nuxt.close()
62+
})
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
.global-css-selector {
2+
color: red;
3+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
<template>
2+
<div>
3+
<nuxt/>
4+
<p>I have custom layouts directory</p>
5+
</div>
6+
</template>
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
export default function (context) {
2+
context.userAgent = process.server ? context.req.headers['user-agent'] : navigator.userAgent
3+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<template>
2+
<div>
3+
<h1>I have custom pages directory</h1>
4+
</div>
5+
</template>
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
<template>
2+
<pre>{{ userAgent }}</pre>
3+
</template>
4+
5+
<script>
6+
export default {
7+
middleware: 'user-agent',
8+
asyncData({ userAgent }) {
9+
return { userAgent }
10+
}
11+
}
12+
</script>
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
A test here :)
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import Vue from 'vue'
2+
import Vuex from 'vuex'
3+
4+
Vue.use(Vuex)
5+
6+
const store = () => new Vuex.Store({
7+
state: {
8+
counter: 0
9+
},
10+
mutations: {
11+
increment(state) {
12+
state.counter++
13+
}
14+
}
15+
})
16+
17+
export default store
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
module.exports = {
2+
css: [{ src: '~/custom-assets/app.css' }],
3+
dir: {
4+
assets: 'custom-assets',
5+
layouts: 'custom-layouts',
6+
middleware: 'custom-middleware',
7+
pages: 'custom-pages',
8+
static: 'custom-static',
9+
store: 'custom-store'
10+
}
11+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"name": "custom-dirs",
3+
"version": "1.0.0",
4+
"dependencies": {}
5+
}

0 commit comments

Comments
 (0)