Skip to content

Commit

Permalink
fix(webpack): use compact name for concatenated modules (#7639)
Browse files Browse the repository at this point in the history
[release]
  • Loading branch information
pi0 committed Jun 30, 2020
1 parent 250a1c3 commit 1edac29
Show file tree
Hide file tree
Showing 18 changed files with 124 additions and 72 deletions.
11 changes: 7 additions & 4 deletions packages/config/src/config/build.js
Expand Up @@ -14,8 +14,8 @@ export default () => ({
serverURLPolyfill: 'url',
filenames: {
// { isDev, isClient, isServer }
app: ({ isDev, isModern }) => isDev ? `${isModern ? 'modern-' : ''}[name].js` : '[name].[contenthash:7].js',
chunk: ({ isDev, isModern }) => isDev ? `${isModern ? 'modern-' : ''}[name].js` : '[name].[contenthash:7].js',
app: ({ isDev, isModern }) => isDev ? `[name]${isModern ? '.modern' : ''}.js` : `[name].[contenthash:7]${isModern ? '.modern' : ''}.js`,
chunk: ({ isDev, isModern }) => isDev ? `[name]${isModern ? '.modern' : ''}.js` : `[name].[contenthash:7]${isModern ? '.modern' : ''}.js`,
css: ({ isDev }) => isDev ? '[name].css' : '[name].[contenthash:7].css',
img: ({ isDev }) => isDev ? '[path][name].[ext]' : 'img/[name].[contenthash:7].[ext]',
font: ({ isDev }) => isDev ? '[path][name].[ext]' : 'fonts/[name].[contenthash:7].[ext]',
Expand Down Expand Up @@ -62,9 +62,12 @@ export default () => ({
minimizer: undefined,
splitChunks: {
chunks: 'all',
automaticNameDelimiter: '.',
name: undefined,
cacheGroups: {}
cacheGroups: {
default: {
name: undefined
}
}
}
},
splitChunks: {
Expand Down
7 changes: 5 additions & 2 deletions packages/config/test/__snapshots__/options.test.js.snap
Expand Up @@ -112,8 +112,11 @@ Object {
"minimizer": undefined,
"runtimeChunk": "single",
"splitChunks": Object {
"automaticNameDelimiter": ".",
"cacheGroups": Object {},
"cacheGroups": Object {
"default": Object {
"name": undefined,
},
},
"chunks": "all",
"name": undefined,
},
Expand Down
14 changes: 10 additions & 4 deletions packages/config/test/config/__snapshots__/index.test.js.snap
Expand Up @@ -88,8 +88,11 @@ Object {
"minimizer": undefined,
"runtimeChunk": "single",
"splitChunks": Object {
"automaticNameDelimiter": ".",
"cacheGroups": Object {},
"cacheGroups": Object {
"default": Object {
"name": undefined,
},
},
"chunks": "all",
"name": undefined,
},
Expand Down Expand Up @@ -458,8 +461,11 @@ Object {
"minimizer": undefined,
"runtimeChunk": "single",
"splitChunks": Object {
"automaticNameDelimiter": ".",
"cacheGroups": Object {},
"cacheGroups": Object {
"default": Object {
"name": undefined,
},
},
"chunks": "all",
"name": undefined,
},
Expand Down
4 changes: 2 additions & 2 deletions packages/config/test/config/build.test.js
Expand Up @@ -26,7 +26,7 @@ describe('config: build', () => {
test('should return modern filenames', () => {
const { filenames } = buildConfig()
const env = { isDev: true, isModern: true }
expect(filenames.app(env)).toEqual('modern-[name].js')
expect(filenames.chunk(env)).toEqual('modern-[name].js')
expect(filenames.app(env)).toEqual('[name].modern.js')
expect(filenames.chunk(env)).toEqual('[name].modern.js')
})
})
5 changes: 2 additions & 3 deletions packages/utils/src/resolve.js
Expand Up @@ -17,10 +17,9 @@ export const wp = function wp (p = '') {
return p
}

// Kept for backward compat (modules may use it from template context)
export const wChunk = function wChunk (p = '') {
// workaround for SplitChunksPlugin that generate names starting from . for catchAll pages _.vue
// consider using https://webpack.js.org/configuration/output/#outputfilename for more robust control over filename generation
return p.replace('_', '[_]')
return p
}

const reqSep = /\//g
Expand Down
32 changes: 19 additions & 13 deletions packages/webpack/src/config/client.js
Expand Up @@ -38,16 +38,6 @@ export default class WebpackClientConfig extends WebpackBaseConfig {
}
}

getFileName (...args) {
if (this.buildContext.buildOptions.analyze) {
const [key] = args
if (['app', 'chunk'].includes(key)) {
return `${this.isModern ? 'modern-' : ''}[name].js`
}
}
return super.getFileName(...args)
}

env () {
return Object.assign(
super.env(),
Expand All @@ -63,18 +53,34 @@ export default class WebpackClientConfig extends WebpackBaseConfig {

optimization () {
const optimization = super.optimization()
const { splitChunks } = optimization
const { cacheGroups } = splitChunks

// Small, known and common modules which are usually used project-wise
// Sum of them may not be more than 244 KiB
if (
this.buildContext.buildOptions.splitChunks.commons === true &&
optimization.splitChunks.cacheGroups.commons === undefined
cacheGroups.commons === undefined
) {
optimization.splitChunks.cacheGroups.commons = {
cacheGroups.commons = {
test: /node_modules[\\/](vue|vue-loader|vue-router|vuex|vue-meta|core-js|@babel\/runtime|axios|webpack|setimmediate|timers-browserify|process|regenerator-runtime|cookie|js-cookie|is-buffer|dotprop|nuxt\.js)[\\/]/,
chunks: 'all',
priority: 10,
name: true
name: true,
automaticNameDelimiter: '/'
}
}

if (!this.dev && cacheGroups.default && cacheGroups.default.name === undefined) {
cacheGroups.default.name = (_module, chunks) => {
// Use default name for single chunks
if (chunks.length === 1) {
return chunks[0].name || ''
}
// Use compact name for concatinated modules
return 'commons/' + chunks.filter(c => c.name).map(c =>
c.name.replace(/\//g, '.').replace(/_/g, '').replace('pages.', '')
).join('~')
}
}

Expand Down
20 changes: 10 additions & 10 deletions test/dev/modern.client.test.js
@@ -1,4 +1,4 @@
import { loadFixture, getPort, Nuxt, rp, wChunk } from '../utils'
import { loadFixture, getPort, Nuxt, rp } from '../utils'

let nuxt, port
const url = route => 'http://localhost:' + port + route
Expand All @@ -16,28 +16,28 @@ describe('modern client mode (SSR)', () => {
test('should contain nomodule legacy resources', async () => {
const { body: response } = await rp(url('/'))
expect(response).toContain('script nomodule crossorigin="use-credentials" src="/_nuxt/app.js')
expect(response).toContain('script nomodule crossorigin="use-credentials" src="/_nuxt/commons.app.js')
expect(response).toContain('script nomodule crossorigin="use-credentials" src="/_nuxt/commons/app.js')
})

test('should contain module modern resources', async () => {
const { body: response } = await rp(url('/'))
expect(response).toContain('<script type="module" crossorigin="use-credentials" src="/_nuxt/modern-app.js"')
expect(response).toContain('<script type="module" crossorigin="use-credentials" src="/_nuxt/modern-commons.app.js"')
expect(response).toContain('<script type="module" crossorigin="use-credentials" src="/_nuxt/app.modern.js"')
expect(response).toContain('<script type="module" crossorigin="use-credentials" src="/_nuxt/commons/app.modern.js"')
})

test('should contain module preload resources', async () => {
const { body: response } = await rp(url('/'))
expect(response).toContain('<link rel="modulepreload" crossorigin="use-credentials" href="/_nuxt/modern-app.js" as="script">')
expect(response).toContain('<link rel="modulepreload" crossorigin="use-credentials" href="/_nuxt/modern-commons.app.js" as="script">')
expect(response).toContain('<link rel="modulepreload" crossorigin="use-credentials" href="/_nuxt/app.modern.js" as="script">')
expect(response).toContain('<link rel="modulepreload" crossorigin="use-credentials" href="/_nuxt/commons/app.modern.js" as="script">')
})

test('should contain module http2 pushed resources', async () => {
const { headers: { link } } = await rp(url('/'))
expect(link).toEqual([
'</_nuxt/modern-runtime.js>; rel=modulepreload; crossorigin=use-credentials; as=script',
'</_nuxt/modern-commons.app.js>; rel=modulepreload; crossorigin=use-credentials; as=script',
'</_nuxt/modern-app.js>; rel=modulepreload; crossorigin=use-credentials; as=script',
`</_nuxt/modern-${wChunk('pages/index.js')}>; rel=modulepreload; crossorigin=use-credentials; as=script`
'</_nuxt/runtime.modern.js>; rel=modulepreload; crossorigin=use-credentials; as=script',
'</_nuxt/commons/app.modern.js>; rel=modulepreload; crossorigin=use-credentials; as=script',
'</_nuxt/app.modern.js>; rel=modulepreload; crossorigin=use-credentials; as=script',
`</_nuxt/pages/index.modern.js>; rel=modulepreload; crossorigin=use-credentials; as=script`
].join(', '))
})

Expand Down
24 changes: 12 additions & 12 deletions test/dev/modern.server.test.js
Expand Up @@ -24,30 +24,30 @@ describe('modern server mode', () => {
test('should use legacy resources by default', async () => {
const { body: response } = await rp(url('/'))
expect(response).toContain('/_nuxt/app.js')
expect(response).toContain('/_nuxt/commons.app.js')
expect(response).toContain('/_nuxt/commons/app.js')
})

test('should use modern resources for modern resources', async () => {
const { body: response } = await rp(url('/'), { headers: { 'user-agent': modernUA } })
expect(response).toContain('/_nuxt/modern-app.js')
expect(response).toContain('/_nuxt/modern-commons.app.js')
expect(response).toContain('/_nuxt/app.modern.js')
expect(response).toContain('/_nuxt/commons/app.modern.js')
})

test('should include es6 syntax in modern resources', async () => {
const { body: response } = await rp(url(`/_nuxt/modern-${wChunk('pages/index.js')}`))
expect(response).toContain('arrow: () => {')
const { body: response } = await rp(url(`/_nuxt/pages/index.modern.js`))
expect(response).toContain('=>')
})

test('should not include es6 syntax in normal resources', async () => {
const { body: response } = await rp(url(`/_nuxt/${wChunk('pages/index.js')}`))
expect(response).toContain('arrow: function arrow() {')
const { body: response } = await rp(url(`/_nuxt/pages/index.js`))
expect(response).not.toContain('=>')
})

test('should contain legacy http2 pushed resources', async () => {
const { headers: { link } } = await rp(url('/'))
expect(link).toEqual([
'</_nuxt/runtime.js>; rel=preload; crossorigin=use-credentials; as=script',
'</_nuxt/commons.app.js>; rel=preload; crossorigin=use-credentials; as=script',
'</_nuxt/commons/app.js>; rel=preload; crossorigin=use-credentials; as=script',
'</_nuxt/app.js>; rel=preload; crossorigin=use-credentials; as=script',
`</_nuxt/${wChunk('pages/index.js')}>; rel=preload; crossorigin=use-credentials; as=script`
].join(', '))
Expand All @@ -58,10 +58,10 @@ describe('modern server mode', () => {
headers: { 'user-agent': modernUA }
})
expect(link).toEqual([
'</_nuxt/modern-runtime.js>; rel=preload; crossorigin=use-credentials; as=script',
'</_nuxt/modern-commons.app.js>; rel=preload; crossorigin=use-credentials; as=script',
'</_nuxt/modern-app.js>; rel=preload; crossorigin=use-credentials; as=script',
`</_nuxt/modern-${wChunk('pages/index.js')}>; rel=preload; crossorigin=use-credentials; as=script`
'</_nuxt/runtime.modern.js>; rel=preload; crossorigin=use-credentials; as=script',
'</_nuxt/commons/app.modern.js>; rel=preload; crossorigin=use-credentials; as=script',
'</_nuxt/app.modern.js>; rel=preload; crossorigin=use-credentials; as=script',
`</_nuxt/pages/index.modern.js>; rel=preload; crossorigin=use-credentials; as=script`
].join(', '))
})

Expand Down
20 changes: 10 additions & 10 deletions test/dev/modern.spa.test.js
Expand Up @@ -24,34 +24,34 @@ describe('modern client mode (SPA)', () => {
test('should contain nomodule legacy resources', async () => {
const { body: response } = await rp(url('/'))
expect(response).toContain('src="/_nuxt/app.js" crossorigin="use-credentials" nomodule')
expect(response).toContain('src="/_nuxt/commons.app.js" crossorigin="use-credentials" nomodule')
expect(response).toContain('src="/_nuxt/commons/app.js" crossorigin="use-credentials" nomodule')
})

test('should contain module modern resources', async () => {
const { body: response } = await rp(url('/'))
expect(response).toContain('<script src="/_nuxt/modern-app.js" type="module" crossorigin="use-credentials"')
expect(response).toContain('<script src="/_nuxt/modern-commons.app.js" type="module" crossorigin="use-credentials"')
expect(response).toContain('<script src="/_nuxt/app.modern.js" type="module" crossorigin="use-credentials"')
expect(response).toContain('<script src="/_nuxt/commons/app.modern.js" type="module" crossorigin="use-credentials"')
})

test('should contain legacy preload resources', async () => {
const { body: response } = await rp(url('/'))
expect(response).toContain('<link rel="preload" crossorigin="use-credentials" href="/_nuxt/app.js" as="script">')
expect(response).toContain('<link rel="preload" crossorigin="use-credentials" href="/_nuxt/commons.app.js" as="script">')
expect(response).toContain('<link rel="preload" crossorigin="use-credentials" href="/_nuxt/commons/app.js" as="script">')
})

test('should contain legacy http2 pushed resources', async () => {
const { headers: { link } } = await rp(url('/'))
expect(link).toEqual([
'</_nuxt/runtime.js>; rel=preload; crossorigin=use-credentials; as=script',
'</_nuxt/commons.app.js>; rel=preload; crossorigin=use-credentials; as=script',
'</_nuxt/commons/app.js>; rel=preload; crossorigin=use-credentials; as=script',
'</_nuxt/app.js>; rel=preload; crossorigin=use-credentials; as=script'
].join(', '))
})

test('should contain modern preload resources', async () => {
const { body: response } = await rp(url('/'), { headers: { 'user-agent': modernUA } })
expect(response).toContain('<link rel="modulepreload" crossorigin="use-credentials" href="/_nuxt/modern-app.js" as="script">')
expect(response).toContain('<link rel="modulepreload" crossorigin="use-credentials" href="/_nuxt/modern-commons.app.js" as="script">')
expect(response).toContain('<link rel="modulepreload" crossorigin="use-credentials" href="/_nuxt/app.modern.js" as="script">')
expect(response).toContain('<link rel="modulepreload" crossorigin="use-credentials" href="/_nuxt/commons/app.modern.js" as="script">')
})

test('should contain safari nomodule fix', async () => {
Expand All @@ -62,9 +62,9 @@ describe('modern client mode (SPA)', () => {
test('should contain modern http2 pushed resources', async () => {
const { headers: { link } } = await rp(url('/'), { headers: { 'user-agent': modernUA } })
expect(link).toEqual([
'</_nuxt/modern-runtime.js>; rel=modulepreload; crossorigin=use-credentials; as=script',
'</_nuxt/modern-commons.app.js>; rel=modulepreload; crossorigin=use-credentials; as=script',
'</_nuxt/modern-app.js>; rel=modulepreload; crossorigin=use-credentials; as=script'
'</_nuxt/runtime.modern.js>; rel=modulepreload; crossorigin=use-credentials; as=script',
'</_nuxt/commons/app.modern.js>; rel=modulepreload; crossorigin=use-credentials; as=script',
'</_nuxt/app.modern.js>; rel=modulepreload; crossorigin=use-credentials; as=script'
].join(', '))
})

Expand Down
2 changes: 1 addition & 1 deletion test/dev/spa.test.js
Expand Up @@ -35,7 +35,7 @@ function spaTests ({ isHashMode }) {
test('/ (include preload and prefetch resources)', async () => {
const { head } = await renderRoute('/')
expect(head).toMatch('<link rel="preload" href="/_nuxt/runtime.js" as="script">')
expect(head).toMatch('<link rel="preload" href="/_nuxt/commons.app.js" as="script">')
expect(head).toMatch('<link rel="preload" href="/_nuxt/commons/app.js" as="script">')
expect(head).toMatch('<link rel="preload" href="/_nuxt/app.js" as="script">')
expect(head).toMatch(`<link rel="prefetch" href="/_nuxt/${wChunk('pages/custom.js')}">`)
expect(head).toMatch(`<link rel="prefetch" href="/_nuxt/${wChunk('pages/error-handler-async.js')}">`)
Expand Down
5 changes: 0 additions & 5 deletions test/dev/with-config.test.js
Expand Up @@ -34,11 +34,6 @@ describe('with-config', () => {
expect(html).toContain('<h1>I have custom configurations</h1>')
})

test('/ (asset name for analyze mode)', async () => {
const { html } = await nuxt.server.renderRoute('/')
expect(html).toContain('<script src="/test/orion/app.js"')
})

test('/ (global styles inlined)', async () => {
const window = await nuxt.server.renderAndGetWindow(url('/test/'))
const html = window.document.head.innerHTML
Expand Down
8 changes: 2 additions & 6 deletions test/fixtures/modern/nuxt.config.js
Expand Up @@ -2,12 +2,8 @@ export default {
modern: true,
build: {
filenames: {
app: ({ isModern }) => {
return `${isModern ? 'modern-' : ''}[name].js`
},
chunk: ({ isModern }) => {
return `${isModern ? 'modern-' : ''}[name].js`
}
app: ({ isModern }) => `[name]${isModern ? '.modern' : ''}.js`,
chunk: ({ isModern }) => `[name]${isModern ? '.modern' : ''}.js`
}
},
render: {
Expand Down
19 changes: 19 additions & 0 deletions test/fixtures/shared-chunk/components/shared-vendor.vue
@@ -0,0 +1,19 @@
<template>
<div>
{{ test }}
</div>
</template>

<script>
import _ from 'lodash'
import $ from 'cheerio'
export default {
data () {
$('<a>A</a>')
return {
test: _.startCase('lodash')
}
}
}
</script>
5 changes: 5 additions & 0 deletions test/fixtures/shared-chunk/components/shared.vue

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions test/fixtures/shared-chunk/nuxt.config.js
@@ -0,0 +1,3 @@
export default {
components: true
}
6 changes: 6 additions & 0 deletions test/fixtures/shared-chunk/pages/_cat/_id/_sub.vue
@@ -0,0 +1,6 @@
<template>
<div>
<Shared />
<SharedVendor />
</div>
</template>
5 changes: 5 additions & 0 deletions test/fixtures/shared-chunk/pages/index.vue
@@ -0,0 +1,5 @@
<template>
<div>
<SharedVendor />
</div>
</template>
6 changes: 6 additions & 0 deletions test/fixtures/shared-chunk/pages/product/_id.vue
@@ -0,0 +1,6 @@
<template>
<div>
<Shared />
<SharedVendor />
</div>
</template>

0 comments on commit 1edac29

Please sign in to comment.