mirror of
https://github.com/nuxt/nuxt.git
synced 2024-11-30 09:27:13 +00:00
fest: add build.corssorgin (#4472)
This commit is contained in:
parent
9c15c18d1b
commit
e6808c57ef
@ -5,6 +5,7 @@ export default () => ({
|
|||||||
analyze: false,
|
analyze: false,
|
||||||
profile: process.argv.includes('--profile'),
|
profile: process.argv.includes('--profile'),
|
||||||
extractCSS: false,
|
extractCSS: false,
|
||||||
|
crossorigin: undefined,
|
||||||
cssSourceMap: undefined,
|
cssSourceMap: undefined,
|
||||||
ssr: undefined,
|
ssr: undefined,
|
||||||
parallel: false,
|
parallel: false,
|
||||||
|
@ -52,7 +52,7 @@ export default ({ options, nuxt, renderRoute, resources }) => async function nux
|
|||||||
|
|
||||||
const links = pushAssets
|
const links = pushAssets
|
||||||
? pushAssets(req, res, publicPath, preloadFiles)
|
? pushAssets(req, res, publicPath, preloadFiles)
|
||||||
: defaultPushAssets(preloadFiles, shouldPush, publicPath, options.dev)
|
: defaultPushAssets(preloadFiles, shouldPush, publicPath, options)
|
||||||
|
|
||||||
// Pass with single Link header
|
// Pass with single Link header
|
||||||
// https://blog.cloudflare.com/http-2-server-push-with-multiple-assets-per-link-header
|
// https://blog.cloudflare.com/http-2-server-push-with-multiple-assets-per-link-header
|
||||||
@ -87,13 +87,13 @@ export default ({ options, nuxt, renderRoute, resources }) => async function nux
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const defaultPushAssets = (preloadFiles, shouldPush, publicPath, isDev) => {
|
const defaultPushAssets = (preloadFiles, shouldPush, publicPath, options) => {
|
||||||
if (shouldPush && isDev) {
|
if (shouldPush && options.dev) {
|
||||||
consola.warn('http2.shouldPush is deprecated. Use http2.pushAssets function')
|
consola.warn('http2.shouldPush is deprecated. Use http2.pushAssets function')
|
||||||
}
|
}
|
||||||
|
|
||||||
const links = []
|
const links = []
|
||||||
preloadFiles.forEach(({ file, asType, fileWithoutQuery }) => {
|
preloadFiles.forEach(({ file, asType, fileWithoutQuery, modern }) => {
|
||||||
// By default, we only preload scripts or css
|
// By default, we only preload scripts or css
|
||||||
/* istanbul ignore if */
|
/* istanbul ignore if */
|
||||||
if (!shouldPush && asType !== 'script' && asType !== 'style') {
|
if (!shouldPush && asType !== 'script' && asType !== 'style') {
|
||||||
@ -105,7 +105,11 @@ const defaultPushAssets = (preloadFiles, shouldPush, publicPath, isDev) => {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
links.push(`<${publicPath}${file}>; rel=preload; as=${asType}`)
|
const crossorigin = options.build.crossorigin
|
||||||
|
const cors = `${crossorigin ? ` crossorigin=${crossorigin};` : ''}`
|
||||||
|
const ref = modern ? 'modulepreload' : 'preload'
|
||||||
|
|
||||||
|
links.push(`<${publicPath}${file}>; rel=${ref};${cors} as=${asType}`)
|
||||||
})
|
})
|
||||||
return links
|
return links
|
||||||
}
|
}
|
||||||
|
@ -55,8 +55,10 @@ export default class VueRenderer {
|
|||||||
return context.renderScripts().replace(scriptPattern, (scriptTag, jsFile) => {
|
return context.renderScripts().replace(scriptPattern, (scriptTag, jsFile) => {
|
||||||
const legacyJsFile = jsFile.replace(publicPath, '')
|
const legacyJsFile = jsFile.replace(publicPath, '')
|
||||||
const modernJsFile = this.assetsMapping[legacyJsFile]
|
const modernJsFile = this.assetsMapping[legacyJsFile]
|
||||||
const moduleTag = scriptTag.replace('<script', '<script type="module"').replace(legacyJsFile, modernJsFile)
|
const crossorigin = this.context.options.build.crossorigin
|
||||||
const noModuleTag = scriptTag.replace('<script', '<script nomodule')
|
const cors = `${crossorigin ? ` crossorigin="${crossorigin}"` : ''}`
|
||||||
|
const moduleTag = scriptTag.replace('<script', `<script type="module"${cors}`).replace(legacyJsFile, modernJsFile)
|
||||||
|
const noModuleTag = scriptTag.replace('<script', `<script nomodule${cors}`)
|
||||||
return noModuleTag + moduleTag
|
return noModuleTag + moduleTag
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -66,7 +68,7 @@ export default class VueRenderer {
|
|||||||
getModernFiles(legacyFiles = []) {
|
getModernFiles(legacyFiles = []) {
|
||||||
const modernFiles = []
|
const modernFiles = []
|
||||||
for (const legacyJsFile of legacyFiles) {
|
for (const legacyJsFile of legacyFiles) {
|
||||||
const modernFile = { ...legacyJsFile }
|
const modernFile = { ...legacyJsFile, modern: true }
|
||||||
if (modernFile.asType === 'script') {
|
if (modernFile.asType === 'script') {
|
||||||
const file = this.assetsMapping[legacyJsFile.file]
|
const file = this.assetsMapping[legacyJsFile.file]
|
||||||
modernFile.file = file
|
modernFile.file = file
|
||||||
@ -91,7 +93,9 @@ export default class VueRenderer {
|
|||||||
return context.renderResourceHints().replace(linkPattern, (linkTag, jsFile) => {
|
return context.renderResourceHints().replace(linkPattern, (linkTag, jsFile) => {
|
||||||
const legacyJsFile = jsFile.replace(publicPath, '')
|
const legacyJsFile = jsFile.replace(publicPath, '')
|
||||||
const modernJsFile = this.assetsMapping[legacyJsFile]
|
const modernJsFile = this.assetsMapping[legacyJsFile]
|
||||||
return linkTag.replace('rel="preload"', 'rel="modulepreload"').replace(legacyJsFile, modernJsFile)
|
const crossorigin = this.context.options.build.crossorigin
|
||||||
|
const cors = `${crossorigin ? ` crossorigin="${crossorigin}"` : ''}`
|
||||||
|
return linkTag.replace('rel="preload"', `rel="modulepreload"${cors}`).replace(legacyJsFile, modernJsFile)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
return context.renderResourceHints()
|
return context.renderResourceHints()
|
||||||
|
@ -5,6 +5,7 @@ import BundleAnalyzer from 'webpack-bundle-analyzer'
|
|||||||
import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin'
|
import OptimizeCSSAssetsPlugin from 'optimize-css-assets-webpack-plugin'
|
||||||
import FriendlyErrorsWebpackPlugin from '@nuxt/friendly-errors-webpack-plugin'
|
import FriendlyErrorsWebpackPlugin from '@nuxt/friendly-errors-webpack-plugin'
|
||||||
|
|
||||||
|
import CorsPlugin from '../plugins/vue/cors'
|
||||||
import ModernModePlugin from '../plugins/vue/modern'
|
import ModernModePlugin from '../plugins/vue/modern'
|
||||||
import VueSSRClientPlugin from '../plugins/vue/client'
|
import VueSSRClientPlugin from '../plugins/vue/client'
|
||||||
import WebpackBaseConfig from './base'
|
import WebpackBaseConfig from './base'
|
||||||
@ -124,6 +125,12 @@ export default class WebpackClientConfig extends WebpackBaseConfig {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.options.build.crossorigin) {
|
||||||
|
plugins.push(new CorsPlugin({
|
||||||
|
crossorigin: this.options.build.crossorigin
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
return plugins
|
return plugins
|
||||||
}
|
}
|
||||||
|
|
||||||
|
22
packages/webpack/src/plugins/vue/cors.js
Normal file
22
packages/webpack/src/plugins/vue/cors.js
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
export default class CorsPlugin {
|
||||||
|
constructor({ crossorigin }) {
|
||||||
|
this.crossorigin = crossorigin
|
||||||
|
}
|
||||||
|
|
||||||
|
apply(compiler) {
|
||||||
|
const ID = `vue-cors-plugin`
|
||||||
|
compiler.hooks.compilation.tap(ID, (compilation) => {
|
||||||
|
compilation.hooks.htmlWebpackPluginAlterAssetTags.tap(ID, (data) => {
|
||||||
|
if (this.crossorigin != null) {
|
||||||
|
[...data.head, ...data.body].forEach((tag) => {
|
||||||
|
if (tag.tagName === 'script' || tag.tagName === 'link') {
|
||||||
|
if (tag.attributes) {
|
||||||
|
tag.attributes.crossorigin = this.crossorigin
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
1
test/fixtures/modern/nuxt.config.js
vendored
1
test/fixtures/modern/nuxt.config.js
vendored
@ -1,6 +1,7 @@
|
|||||||
export default {
|
export default {
|
||||||
modern: true,
|
modern: true,
|
||||||
build: {
|
build: {
|
||||||
|
crossorigin: 'use-credentials',
|
||||||
filenames: {
|
filenames: {
|
||||||
app: ({ isModern }) => {
|
app: ({ isModern }) => {
|
||||||
return `${isModern ? 'modern-' : ''}[name].js`
|
return `${isModern ? 'modern-' : ''}[name].js`
|
||||||
|
@ -13,29 +13,29 @@ describe('modern client mode (SSR)', () => {
|
|||||||
|
|
||||||
test('should contain nomodule legacy resources', async () => {
|
test('should contain nomodule legacy resources', async () => {
|
||||||
const response = await rp(url('/'))
|
const response = await rp(url('/'))
|
||||||
expect(response).toContain('script nomodule src="/_nuxt/app.js')
|
expect(response).toContain('script nomodule crossorigin="use-credentials" src="/_nuxt/app.js')
|
||||||
expect(response).toContain('script nomodule 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 () => {
|
test('should contain module modern resources', async () => {
|
||||||
const response = await rp(url('/'))
|
const response = await rp(url('/'))
|
||||||
expect(response).toContain('<script type="module" src="/_nuxt/modern-app.js"')
|
expect(response).toContain('<script type="module" crossorigin="use-credentials" src="/_nuxt/modern-app.js"')
|
||||||
expect(response).toContain('<script type="module" src="/_nuxt/modern-commons.app.js"')
|
expect(response).toContain('<script type="module" crossorigin="use-credentials" src="/_nuxt/modern-commons.app.js"')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should contain module preload resources', async () => {
|
test('should contain module preload resources', async () => {
|
||||||
const response = await rp(url('/'))
|
const response = await rp(url('/'))
|
||||||
expect(response).toContain('<link rel="modulepreload" href="/_nuxt/modern-app.js" as="script">')
|
expect(response).toContain('<link rel="modulepreload" crossorigin="use-credentials" href="/_nuxt/modern-app.js" as="script">')
|
||||||
expect(response).toContain('<link rel="modulepreload" href="/_nuxt/modern-commons.app.js" as="script">')
|
expect(response).toContain('<link rel="modulepreload" crossorigin="use-credentials" href="/_nuxt/modern-commons.app.js" as="script">')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should contain module http2 pushed resources', async () => {
|
test('should contain module http2 pushed resources', async () => {
|
||||||
const { headers: { link } } = await rp(url('/'), { resolveWithFullResponse: true })
|
const { headers: { link } } = await rp(url('/'), { resolveWithFullResponse: true })
|
||||||
expect(link).toEqual([
|
expect(link).toEqual([
|
||||||
'</_nuxt/modern-runtime.js>; rel=preload; as=script',
|
'</_nuxt/modern-runtime.js>; rel=modulepreload; crossorigin=use-credentials; as=script',
|
||||||
'</_nuxt/modern-commons.app.js>; rel=preload; as=script',
|
'</_nuxt/modern-commons.app.js>; rel=modulepreload; crossorigin=use-credentials; as=script',
|
||||||
'</_nuxt/modern-app.js>; rel=preload; as=script',
|
'</_nuxt/modern-app.js>; rel=modulepreload; crossorigin=use-credentials; as=script',
|
||||||
`</_nuxt/modern-${wChunk('pages/index.js')}>; rel=preload; as=script`
|
`</_nuxt/modern-${wChunk('pages/index.js')}>; rel=modulepreload; crossorigin=use-credentials; as=script`
|
||||||
].join(', '))
|
].join(', '))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -47,10 +47,10 @@ describe('modern server mode', () => {
|
|||||||
resolveWithFullResponse: true
|
resolveWithFullResponse: true
|
||||||
})
|
})
|
||||||
expect(link).toEqual([
|
expect(link).toEqual([
|
||||||
'</_nuxt/runtime.js>; rel=preload; as=script',
|
'</_nuxt/runtime.js>; rel=preload; crossorigin=use-credentials; as=script',
|
||||||
'</_nuxt/commons.app.js>; rel=preload; as=script',
|
'</_nuxt/commons.app.js>; rel=preload; crossorigin=use-credentials; as=script',
|
||||||
'</_nuxt/app.js>; rel=preload; as=script',
|
'</_nuxt/app.js>; rel=preload; crossorigin=use-credentials; as=script',
|
||||||
`</_nuxt/${wChunk('pages/index.js')}>; rel=preload; as=script`
|
`</_nuxt/${wChunk('pages/index.js')}>; rel=preload; crossorigin=use-credentials; as=script`
|
||||||
].join(', '))
|
].join(', '))
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -60,10 +60,10 @@ describe('modern server mode', () => {
|
|||||||
resolveWithFullResponse: true
|
resolveWithFullResponse: true
|
||||||
})
|
})
|
||||||
expect(link).toEqual([
|
expect(link).toEqual([
|
||||||
'</_nuxt/modern-runtime.js>; rel=preload; as=script',
|
'</_nuxt/modern-runtime.js>; rel=preload; crossorigin=use-credentials; as=script',
|
||||||
'</_nuxt/modern-commons.app.js>; rel=preload; as=script',
|
'</_nuxt/modern-commons.app.js>; rel=preload; crossorigin=use-credentials; as=script',
|
||||||
'</_nuxt/modern-app.js>; rel=preload; as=script',
|
'</_nuxt/modern-app.js>; rel=preload; crossorigin=use-credentials; as=script',
|
||||||
`</_nuxt/modern-${wChunk('pages/index.js')}>; rel=preload; as=script`
|
`</_nuxt/modern-${wChunk('pages/index.js')}>; rel=preload; crossorigin=use-credentials; as=script`
|
||||||
].join(', '))
|
].join(', '))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
@ -21,28 +21,28 @@ describe('modern client mode (SPA)', () => {
|
|||||||
|
|
||||||
test('should contain nomodule legacy resources', async () => {
|
test('should contain nomodule legacy resources', async () => {
|
||||||
const response = await rp(url('/'))
|
const response = await rp(url('/'))
|
||||||
expect(response).toContain('src="/_nuxt/app.js" nomodule')
|
expect(response).toContain('src="/_nuxt/app.js" crossorigin="use-credentials" nomodule')
|
||||||
expect(response).toContain('src="/_nuxt/commons.app.js" nomodule')
|
expect(response).toContain('src="/_nuxt/commons.app.js" crossorigin="use-credentials" nomodule')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should contain module modern resources', async () => {
|
test('should contain module modern resources', async () => {
|
||||||
const response = await rp(url('/'))
|
const response = await rp(url('/'))
|
||||||
expect(response).toContain('<script type="module" src="/_nuxt/modern-app.js"')
|
expect(response).toContain('<script type="module" src="/_nuxt/modern-app.js" crossorigin="use-credentials"')
|
||||||
expect(response).toContain('<script type="module" src="/_nuxt/modern-commons.app.js"')
|
expect(response).toContain('<script type="module" src="/_nuxt/modern-commons.app.js" crossorigin="use-credentials"')
|
||||||
})
|
})
|
||||||
|
|
||||||
test.skip('should contain module preload resources', async () => {
|
test.skip('should contain module preload resources', async () => {
|
||||||
const response = await rp(url('/'))
|
const response = await rp(url('/'))
|
||||||
expect(response).toContain('<link rel="modulepreload" href="/_nuxt/modern-app.js" as="script">')
|
expect(response).toContain('<link rel="modulepreload" crossorigin="use-credentials" href="/_nuxt/modern-app.js" as="script">')
|
||||||
expect(response).toContain('<link rel="modulepreload" href="/_nuxt/modern-commons.app.js" as="script">')
|
expect(response).toContain('<link rel="modulepreload" crossorigin="use-credentials" href="/_nuxt/modern-commons.app.js" as="script">')
|
||||||
})
|
})
|
||||||
|
|
||||||
test('should contain module http2 pushed resources', async () => {
|
test('should contain module http2 pushed resources', async () => {
|
||||||
const { headers: { link } } = await rp(url('/'), { resolveWithFullResponse: true })
|
const { headers: { link } } = await rp(url('/'), { resolveWithFullResponse: true })
|
||||||
expect(link).toEqual([
|
expect(link).toEqual([
|
||||||
'</_nuxt/modern-runtime.js>; rel=preload; as=script',
|
'</_nuxt/modern-runtime.js>; rel=modulepreload; crossorigin=use-credentials; as=script',
|
||||||
'</_nuxt/modern-commons.app.js>; rel=preload; as=script',
|
'</_nuxt/modern-commons.app.js>; rel=modulepreload; crossorigin=use-credentials; as=script',
|
||||||
'</_nuxt/modern-app.js>; rel=preload; as=script'
|
'</_nuxt/modern-app.js>; rel=modulepreload; crossorigin=use-credentials; as=script'
|
||||||
].join(', '))
|
].join(', '))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user