fix(webpack): use compact name for concatenated modules (#7639)

[release]
This commit is contained in:
pooya parsa 2020-06-30 19:47:42 +02:00 committed by GitHub
parent 250a1c3918
commit 1edac29eba
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
18 changed files with 124 additions and 72 deletions

View File

@ -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]',
@ -62,9 +62,12 @@ export default () => ({
minimizer: undefined,
splitChunks: {
chunks: 'all',
automaticNameDelimiter: '.',
name: undefined,
cacheGroups: {}
cacheGroups: {
default: {
name: undefined
}
}
}
},
splitChunks: {

View File

@ -112,8 +112,11 @@ Object {
"minimizer": undefined,
"runtimeChunk": "single",
"splitChunks": Object {
"automaticNameDelimiter": ".",
"cacheGroups": Object {},
"cacheGroups": Object {
"default": Object {
"name": undefined,
},
},
"chunks": "all",
"name": undefined,
},

View File

@ -88,8 +88,11 @@ Object {
"minimizer": undefined,
"runtimeChunk": "single",
"splitChunks": Object {
"automaticNameDelimiter": ".",
"cacheGroups": Object {},
"cacheGroups": Object {
"default": Object {
"name": undefined,
},
},
"chunks": "all",
"name": undefined,
},
@ -458,8 +461,11 @@ Object {
"minimizer": undefined,
"runtimeChunk": "single",
"splitChunks": Object {
"automaticNameDelimiter": ".",
"cacheGroups": Object {},
"cacheGroups": Object {
"default": Object {
"name": undefined,
},
},
"chunks": "all",
"name": undefined,
},

View File

@ -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')
})
})

View File

@ -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

View File

@ -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(),
@ -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('~')
}
}

View File

@ -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
@ -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(', '))
})

View File

@ -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(', '))
@ -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(', '))
})

View File

@ -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 () => {
@ -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(', '))
})

View File

@ -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')}">`)

View File

@ -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

View File

@ -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: {

View File

@ -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>

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,3 @@
export default {
components: true
}

View File

@ -0,0 +1,6 @@
<template>
<div>
<Shared />
<SharedVendor />
</div>
</template>

View File

@ -0,0 +1,5 @@
<template>
<div>
<SharedVendor />
</div>
</template>

View File

@ -0,0 +1,6 @@
<template>
<div>
<Shared />
<SharedVendor />
</div>
</template>