mirror of
https://gitee.com/vuejs/vue.git
synced 2024-12-04 04:57:40 +08:00
inline css links in renderStyles()
This commit is contained in:
parent
3a621d1860
commit
2efc0446b3
@ -3,15 +3,13 @@
|
||||
const path = require('path')
|
||||
const serialize = require('serialize-javascript')
|
||||
|
||||
import { isJS, isCSS } from '../util'
|
||||
import TemplateStream from './template-stream'
|
||||
import { parseTemplate } from './parse-template'
|
||||
import { createMapper } from './create-async-file-mapper'
|
||||
import type { ParsedTemplate } from './parse-template'
|
||||
import type { AsyncFileMapper } from './create-async-file-mapper'
|
||||
|
||||
const JS_RE = /\.js($|\?)/
|
||||
export const isJS = (file: string): boolean => JS_RE.test(file)
|
||||
|
||||
type TemplateRendererOptions = {
|
||||
template: ?string;
|
||||
inject?: boolean;
|
||||
@ -100,8 +98,18 @@ export default class TemplateRenderer {
|
||||
}
|
||||
|
||||
renderStyles (context: Object): string {
|
||||
// context.styles is a getter exposed by vue-style-loader
|
||||
return context.styles || ''
|
||||
const cssFiles = this.clientManifest
|
||||
? this.clientManifest.all.filter(isCSS)
|
||||
: []
|
||||
return (
|
||||
// render links for css files
|
||||
(cssFiles.length
|
||||
? cssFiles.map(file => `<link rel="stylesheet" href="${this.publicPath}/${file}">`).join('')
|
||||
: '') +
|
||||
// context.styles is a getter exposed by vue-style-loader which contains
|
||||
// the inline component styles collected during SSR
|
||||
(context.styles || '')
|
||||
)
|
||||
}
|
||||
|
||||
renderResourceHints (context: Object): string {
|
||||
@ -117,8 +125,8 @@ export default class TemplateRenderer {
|
||||
const ext = path.extname(withoutQuery).slice(1)
|
||||
const type = getPreloadType(ext)
|
||||
const shouldPreload = this.options.shouldPreload
|
||||
// by default, we only preload scripts
|
||||
if (!shouldPreload && type !== 'script') {
|
||||
// by default, we only preload scripts or css
|
||||
if (!shouldPreload && type !== 'script' && type !== 'style') {
|
||||
return ''
|
||||
}
|
||||
// user wants to explicitly control what to preload
|
||||
|
@ -49,9 +49,10 @@ export default class TemplateStream extends Transform {
|
||||
this.push(links)
|
||||
}
|
||||
|
||||
// inline server-rendered CSS collected by vue-style-loader
|
||||
if (this.context.styles) {
|
||||
this.push(this.context.styles)
|
||||
// CSS files and inline server-rendered CSS collected by vue-style-loader
|
||||
const styles = this.renderer.renderStyles(this.context)
|
||||
if (styles) {
|
||||
this.push(styles)
|
||||
}
|
||||
}
|
||||
|
||||
|
5
src/server/util.js
Normal file
5
src/server/util.js
Normal file
@ -0,0 +1,5 @@
|
||||
/* @flow */
|
||||
|
||||
export const isJS = (file: string): boolean => /\.js($|\?)/.test(file)
|
||||
|
||||
export const isCSS = (file: string): boolean => /\.css($|\?)/.test(file)
|
@ -15,20 +15,20 @@ export default class VueSSRClientPlugin {
|
||||
const allFiles = stats.assets
|
||||
.map(a => a.name)
|
||||
|
||||
const initialScripts = Object.keys(stats.entrypoints)
|
||||
const initialFiles = Object.keys(stats.entrypoints)
|
||||
.map(name => stats.entrypoints[name].assets)
|
||||
.reduce((assets, all) => all.concat(assets), [])
|
||||
.filter(isJS)
|
||||
|
||||
const asyncScripts = allFiles
|
||||
const asyncFiles = allFiles
|
||||
.filter(isJS)
|
||||
.filter(file => initialScripts.indexOf(file) < 0)
|
||||
.filter(file => initialFiles.indexOf(file) < 0)
|
||||
|
||||
const manifest = {
|
||||
publicPath: stats.publicPath,
|
||||
all: allFiles,
|
||||
initial: initialScripts,
|
||||
async: asyncScripts,
|
||||
initial: initialFiles,
|
||||
async: asyncFiles,
|
||||
modules: { /* [identifier: string]: Array<index: number> */ }
|
||||
}
|
||||
|
||||
|
@ -21,4 +21,4 @@ export const validate = compiler => {
|
||||
}
|
||||
}
|
||||
|
||||
export const isJS = file => /\.js($|\?)/.test(file)
|
||||
export { isJS, isCSS } from '../util'
|
||||
|
@ -16,7 +16,7 @@ export function compileWithWebpack (file, extraConfig, cb) {
|
||||
loader: require.resolve('./async-loader')
|
||||
},
|
||||
{
|
||||
test: /\.(png|woff2)$/,
|
||||
test: /\.(png|woff2|css)$/,
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: '[name].[ext]'
|
||||
|
@ -1,4 +1,5 @@
|
||||
// import image and font
|
||||
import './test.css'
|
||||
import font from './test.woff2'
|
||||
import image from './test.png'
|
||||
|
||||
|
0
test/ssr/fixtures/test.css
Normal file
0
test/ssr/fixtures/test.css
Normal file
@ -225,11 +225,14 @@ describe('SSR: template option', () => {
|
||||
`<link rel="preload" href="/manifest.js" as="script">` +
|
||||
`<link rel="preload" href="/main.js" as="script">` +
|
||||
`<link rel="preload" href="/0.js" as="script">` +
|
||||
`<link rel="preload" href="/test.css" as="style">` +
|
||||
// images and fonts are only preloaded when explicitly asked for
|
||||
(preloadOtherAssets ? `<link rel="preload" href="/test.png" as="image">` : ``) +
|
||||
(preloadOtherAssets ? `<link rel="preload" href="/test.woff2" as="font" type="font/woff2" crossorigin>` : ``) +
|
||||
// unused chunks should have prefetch
|
||||
`<link rel="prefetch" href="/1.js" as="script">` +
|
||||
// css assets should be loaded
|
||||
`<link rel="stylesheet" href="/test.css">` +
|
||||
`</head><body>` +
|
||||
`<div data-server-rendered="true"><div>async test.woff2 test.png</div></div>` +
|
||||
// manifest chunk should be first
|
||||
@ -243,7 +246,7 @@ describe('SSR: template option', () => {
|
||||
createClientManifestAssertions(false)
|
||||
|
||||
function createClientManifestAssertions (runInNewContext) {
|
||||
it('bundleRenderer + renderToString + clientManifest', done => {
|
||||
it('bundleRenderer + renderToString + clientManifest ()', done => {
|
||||
createRendererWithManifest('split.js', { runInNewContext }, renderer => {
|
||||
renderer.renderToString({}, (err, res) => {
|
||||
expect(err).toBeNull()
|
||||
@ -257,7 +260,7 @@ describe('SSR: template option', () => {
|
||||
createRendererWithManifest('split.js', {
|
||||
runInNewContext,
|
||||
shouldPreload: (file, type) => {
|
||||
if (type === 'image' || type === 'script' || type === 'font') {
|
||||
if (type === 'image' || type === 'script' || type === 'font' || type === 'style') {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@ -278,7 +281,7 @@ describe('SSR: template option', () => {
|
||||
createRendererWithManifest('split.js', {
|
||||
runInNewContext,
|
||||
template: `<html>` +
|
||||
`<head>{{{ renderResourceHints() }}}</head>` +
|
||||
`<head>{{{ renderResourceHints() }}}{{{ renderStyles() }}}</head>` +
|
||||
`<body><!--vue-ssr-outlet-->{{{ renderScripts() }}}</body>` +
|
||||
`</html>`,
|
||||
inject: false
|
||||
@ -303,7 +306,8 @@ describe('SSR: template option', () => {
|
||||
|
||||
const customOutput =
|
||||
`<html><head>${
|
||||
context.renderResourceHints()
|
||||
context.renderResourceHints() +
|
||||
context.renderStyles()
|
||||
}</head><body>${
|
||||
res +
|
||||
context.renderScripts()
|
||||
|
Loading…
Reference in New Issue
Block a user