Skip to content

Commit d1d637f

Browse files
authored
Merge pull request nuxt#3060 from nuxt/feat/asyncChunks
feat: make optimization and splitChunks configurable
2 parents 0d197f1 + cc336c4 commit d1d637f

File tree

11 files changed

+148
-77
lines changed

11 files changed

+148
-77
lines changed

bin/nuxt-build

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ if (argv.help) {
3333
--analyze, -a Launch webpack-bundle-analyzer to optimize your bundles.
3434
--spa Launch in SPA mode
3535
--universal Launch in Universal mode (default)
36+
--generate Generate static version after build
3637
--config-file, -c Path to Nuxt.js config file (default: nuxt.config.js)
3738
--help, -h Displays this message
3839
`)
@@ -65,14 +66,14 @@ const close = () => {
6566
process.exit(0)
6667
}
6768

68-
if (options.mode !== 'spa') {
69-
// -- Build for SSR app --
69+
if (!argv.generate) {
70+
// -- Build only --
7071
builder
7172
.build()
7273
.then(() => close())
7374
.catch(Utils.fatalError)
7475
} else {
75-
// -- Build for SPA app --
76+
// -- Build and generate --
7677
const s = Date.now()
7778

7879
nuxt.hook('generate:distRemoved', () => debug('Destination folder cleaned'))
@@ -92,9 +93,6 @@ if (options.mode !== 'spa') {
9293
}
9394
})
9495

95-
// Disable minify to get exact results of nuxt start
96-
nuxt.options.generate.minify = false
97-
9896
// Generate dist for SPA static deployment
9997
new Generator(nuxt, builder).generate({ build: true }).then(() => {
10098
close()

lib/app/App.js

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import '<%= relativeToBuild(resolvePath(c.src || c)) %>'
55
<% }) %>
66

77
<%= Object.keys(layouts).map(key => {
8-
if (splitPages) {
8+
if (splitChunks.layouts) {
99
return `const _${hash(key)} = () => import('${layouts[key]}' /* webpackChunkName: "${wChunk('layouts/' + key)}" */).then(m => m.default || m)`
1010
} else {
1111
return `import _${hash(key)} from '${layouts[key]}'`
@@ -14,7 +14,7 @@ import '<%= relativeToBuild(resolvePath(c.src || c)) %>'
1414

1515
const layouts = { <%= Object.keys(layouts).map(key => `"_${key}": _${hash(key)}`).join(',') %> }
1616

17-
<% if (splitPages) { %>let resolvedLayouts = {}<% } %>
17+
<% if (splitChunks.layouts) { %>let resolvedLayouts = {}<% } %>
1818

1919
export default {
2020
head: <%= serialize(head).replace('head(', 'function(').replace('titleTemplate(', 'function(') %>,
@@ -78,7 +78,7 @@ export default {
7878
}
7979
},
8080
<% } %>
81-
<% if (splitPages) { %>
81+
<% if (splitChunks.layouts) { %>
8282
setLayout (layout) {
8383
if (!layout || !resolvedLayouts['_' + layout]) layout = 'default'
8484
this.layoutName = layout
@@ -112,6 +112,7 @@ export default {
112112
return this.layout
113113
},
114114
loadLayout(layout) {
115+
if (!layout || !layouts['_' + layout]) layout = 'default'
115116
return Promise.resolve(layouts['_' + layout])
116117
}
117118
<% } %>

lib/app/router.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import Router from 'vue-router'
88
components.push({ _name: route._name, component: route.component, name: route.name, chunkName: route.chunkName })
99
res += tab + '{\n'
1010
res += tab + '\tpath: ' + JSON.stringify(route.path)
11-
res += (route.component) ? ',\n\t' + tab + 'component: ' + (splitPages ? route._name : `() => ${route._name}.default || ${route._name}`) : ''
11+
res += (route.component) ? ',\n\t' + tab + 'component: ' + (splitChunks.pages ? route._name : `() => ${route._name}.default || ${route._name}`) : ''
1212
res += (route.redirect) ? ',\n\t' + tab + 'redirect: ' + JSON.stringify(route.redirect) : ''
1313
res += (route.name) ? ',\n\t' + tab + 'name: ' + JSON.stringify(route.name) : ''
1414
res += (route.children) ? ',\n\t' + tab + 'children: [\n' + recursiveRoutes(routes[i].children, tab + '\t\t', components) + '\n\t' + tab + ']' : ''
@@ -24,7 +24,7 @@ const _routes = recursiveRoutes(router.routes, '\t\t', _components)
2424
const chunkName = wChunk(route.chunkName)
2525
const name = route._name
2626

27-
if (splitPages) {
27+
if (splitChunks.pages) {
2828
return `const ${name} = () => import('${path}' /* webpackChunkName: "${chunkName}" */).then(m => m.default || m)`
2929
} else {
3030
return `import ${name} from '${path}'`

lib/builder/builder.mjs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ export default class Builder {
211211
.map(ext => ext.replace(/^\./, ''))
212212
.join('|'),
213213
messages: this.options.messages,
214-
splitPages: this.options.build.splitPages,
214+
splitChunks: this.options.build.splitChunks,
215215
uniqBy: _.uniqBy,
216216
isDev: this.options.dev,
217217
debug: this.options.debug,

lib/builder/webpack/client.config.mjs

Lines changed: 57 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import webpack from 'webpack'
66
import HTMLPlugin from 'html-webpack-plugin'
77
import StylishPlugin from 'webpack-stylish'
88
import BundleAnalyzer from 'webpack-bundle-analyzer'
9+
import HtmlWebpackInlineSourcePlugin from 'html-webpack-inline-source-plugin'
910

1011
import Debug from 'debug'
1112
import base from './base.config'
@@ -42,6 +43,7 @@ export default function webpackClientConfig() {
4243
filename: 'index.spa.html',
4344
template: this.options.appTemplatePath,
4445
inject: true,
46+
inlineSource: /runtime.*\.js$/,
4547
chunksSortMode: 'dependency'
4648
})
4749
)
@@ -57,6 +59,12 @@ export default function webpackClientConfig() {
5759
)
5860
}
5961

62+
// Enhances html-webpack-plugin functionality by adding the inlineSource option.
63+
// https://github.com/DustinJackson/html-webpack-inline-source-plugin
64+
if (!this.options.dev) {
65+
config.plugins.push(new HtmlWebpackInlineSourcePlugin())
66+
}
67+
6068
// Generate vue-ssr-client-manifest
6169
config.plugins.push(
6270
new VueSSRClientPlugin({
@@ -78,48 +86,59 @@ export default function webpackClientConfig() {
7886
)
7987
)
8088

81-
// Optimization
82-
config.optimization.splitChunks = {
83-
chunks: 'all',
84-
// TODO: remove spa after https://github.com/jantimon/html-webpack-plugin/issues/878 solved
85-
name: this.options.dev || this.options.mode === 'spa',
86-
87-
// Explicit cache groups
88-
cacheGroups: {
89-
// Vue.js core modules
90-
vue: {
91-
test: /node_modules\/(vue|vue-loader|vue-router|vuex|vue-meta)\//,
92-
chunks: 'initial',
93-
name: 'vue',
94-
priority: 10,
95-
enforce: true
96-
},
97-
// Common modules which are usually included in projects
98-
common: {
99-
test: /node_modules\/(core-js|babel-runtime|lodash|es6-promise|moment|axios|webpack|setimediate|timers-browserify|process)\//,
100-
chunks: 'initial',
101-
name: 'common',
102-
priority: 9
103-
},
104-
// Generated templates
105-
main: {
106-
test: /\.nuxt\//,
107-
chunks: 'initial',
108-
name: 'main',
109-
priority: 8
110-
},
111-
// Other vendors inside node_modules
112-
vendor: {
113-
test: /node_modules\//,
114-
chunks: 'initial',
115-
name: 'vendor',
116-
priority: 8
117-
}
89+
// -- Optimization --
90+
config.optimization = this.options.build.optimization
91+
92+
// TODO: remove spa check after https://github.com/jantimon/html-webpack-plugin/issues/878 solved
93+
if (this.options.dev || this.options.mode === 'spa') {
94+
config.optimization.splitChunks.name = true
95+
}
96+
97+
// ... Explicit cache groups
98+
99+
// Vue.js core modules
100+
if (this.options.build.splitChunks.vue) {
101+
config.optimization.splitChunks.cacheGroups.vue = {
102+
test: /node_modules\/(vue|vue-loader|vue-router|vuex|vue-meta)\//,
103+
chunks: 'initial',
104+
name: 'vue',
105+
priority: 10,
106+
enforce: true
107+
}
108+
}
109+
110+
// Common modules which are usually included in projects
111+
if (this.options.build.splitChunks.common) {
112+
config.optimization.splitChunks.cacheGroups.common = {
113+
test: /node_modules\/(core-js|babel-runtime|lodash|es6-promise|moment|axios|webpack|setimediate|timers-browserify|process)\//,
114+
chunks: 'initial',
115+
name: 'common',
116+
priority: 9
117+
}
118+
}
119+
120+
// Generated templates
121+
if (this.options.build.splitChunks.main) {
122+
config.optimization.splitChunks.cacheGroups.main = {
123+
test: /\.nuxt\//,
124+
chunks: 'initial',
125+
name: 'main',
126+
priority: 8
127+
}
128+
}
129+
130+
// Other vendors inside node_modules
131+
if (this.options.build.splitChunks.vendor) {
132+
config.optimization.splitChunks.cacheGroups.vendor = {
133+
test: /node_modules\//,
134+
chunks: 'initial',
135+
name: 'vendor',
136+
priority: 8
118137
}
119138
}
120139

121140
// Create additional runtime chunk for cache boosting
122-
config.optimization.runtimeChunk = true
141+
config.optimization.runtimeChunk = this.options.build.splitChunks.runtime
123142

124143
// --------------------------------------
125144
// Dev specific config

lib/common/nuxt.config.js

Lines changed: 19 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@ export default {
1818
build: {
1919
analyze: false,
2020
profile: process.argv.includes('--profile'),
21-
splitPages: true,
2221
maxChunkSize: false,
2322
extractCSS: false,
2423
cssSourceMap: undefined,
@@ -31,6 +30,20 @@ export default {
3130
},
3231
styleResources: {},
3332
plugins: [],
33+
optimization: {
34+
splitChunks: {
35+
chunks: 'all',
36+
name: false,
37+
cacheGroups: {}
38+
}
39+
},
40+
splitChunks: {
41+
pages: true,
42+
vendor: true,
43+
commons: true,
44+
runtime: true,
45+
layouts: false
46+
},
3447
babel: {
3548
babelrc: false
3649
},
@@ -99,7 +112,7 @@ export default {
99112
duration: 5000,
100113
rtl: false
101114
},
102-
loadingIndicator: {},
115+
loadingIndicator: false,
103116
transition: {
104117
name: 'page',
105118
mode: 'out-in',
@@ -134,8 +147,10 @@ export default {
134147
fallback: false
135148
},
136149
render: {
137-
bundleRenderer: {},
138-
resourceHints: true,
150+
bundleRenderer: {
151+
shouldPrefetch: () => false
152+
},
153+
resourceHints: undefined,
139154
ssr: undefined,
140155
http2: {
141156
push: false,

lib/common/options.mjs

Lines changed: 21 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -103,26 +103,29 @@ Options.from = function (_options) {
103103
options.store = true
104104
}
105105

106-
// Normalize loadingIndicator
107-
if (!isPureObject(options.loadingIndicator)) {
108-
options.loadingIndicator = { name: options.loadingIndicator }
106+
// SPA loadingIndicator
107+
if (options.loadingIndicator) {
108+
// Normalize loadingIndicator
109+
if (!isPureObject(options.loadingIndicator)) {
110+
options.loadingIndicator = { name: options.loadingIndicator }
111+
}
112+
113+
// Apply defaults
114+
options.loadingIndicator = Object.assign(
115+
{
116+
name: 'pulse',
117+
color: '#dbe1ec',
118+
background: 'white'
119+
},
120+
options.loadingIndicator
121+
)
109122
}
110123

111124
// Apply default hash to CSP option
112125
if (options.render.csp === true) {
113126
options.render.csp = { hashAlgorithm: 'sha256' }
114127
}
115128

116-
// Apply defaults to loadingIndicator
117-
options.loadingIndicator = Object.assign(
118-
{
119-
name: 'pulse',
120-
color: '#dbe1ec',
121-
background: 'white'
122-
},
123-
options.loadingIndicator
124-
)
125-
126129
// cssSourceMap
127130
if (options.build.cssSourceMap === undefined) {
128131
options.build.cssSourceMap = options.dev
@@ -138,6 +141,11 @@ Options.from = function (_options) {
138141
options.debug = options.dev
139142
}
140143

144+
// Resource hints
145+
if (options.render.resourceHints === undefined) {
146+
options.render.resourceHints = !options.dev
147+
}
148+
141149
// Normalize ignore
142150
options.ignore = options.ignore ? [].concat(options.ignore) : []
143151

0 commit comments

Comments
 (0)