Skip to content

Commit 2efc044

Browse files
committed
inline css links in renderStyles()
1 parent 3a621d1 commit 2efc044

File tree

9 files changed

+40
-21
lines changed

9 files changed

+40
-21
lines changed

src/server/template-renderer/index.js

+15-7
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@
33
const path = require('path')
44
const serialize = require('serialize-javascript')
55

6+
import { isJS, isCSS } from '../util'
67
import TemplateStream from './template-stream'
78
import { parseTemplate } from './parse-template'
89
import { createMapper } from './create-async-file-mapper'
910
import type { ParsedTemplate } from './parse-template'
1011
import type { AsyncFileMapper } from './create-async-file-mapper'
1112

12-
const JS_RE = /\.js($|\?)/
13-
export const isJS = (file: string): boolean => JS_RE.test(file)
14-
1513
type TemplateRendererOptions = {
1614
template: ?string;
1715
inject?: boolean;
@@ -100,8 +98,18 @@ export default class TemplateRenderer {
10098
}
10199

102100
renderStyles (context: Object): string {
103-
// context.styles is a getter exposed by vue-style-loader
104-
return context.styles || ''
101+
const cssFiles = this.clientManifest
102+
? this.clientManifest.all.filter(isCSS)
103+
: []
104+
return (
105+
// render links for css files
106+
(cssFiles.length
107+
? cssFiles.map(file => `<link rel="stylesheet" href="${this.publicPath}/${file}">`).join('')
108+
: '') +
109+
// context.styles is a getter exposed by vue-style-loader which contains
110+
// the inline component styles collected during SSR
111+
(context.styles || '')
112+
)
105113
}
106114

107115
renderResourceHints (context: Object): string {
@@ -117,8 +125,8 @@ export default class TemplateRenderer {
117125
const ext = path.extname(withoutQuery).slice(1)
118126
const type = getPreloadType(ext)
119127
const shouldPreload = this.options.shouldPreload
120-
// by default, we only preload scripts
121-
if (!shouldPreload && type !== 'script') {
128+
// by default, we only preload scripts or css
129+
if (!shouldPreload && type !== 'script' && type !== 'style') {
122130
return ''
123131
}
124132
// user wants to explicitly control what to preload

src/server/template-renderer/template-stream.js

+4-3
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,10 @@ export default class TemplateStream extends Transform {
4949
this.push(links)
5050
}
5151

52-
// inline server-rendered CSS collected by vue-style-loader
53-
if (this.context.styles) {
54-
this.push(this.context.styles)
52+
// CSS files and inline server-rendered CSS collected by vue-style-loader
53+
const styles = this.renderer.renderStyles(this.context)
54+
if (styles) {
55+
this.push(styles)
5556
}
5657
}
5758

src/server/util.js

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/* @flow */
2+
3+
export const isJS = (file: string): boolean => /\.js($|\?)/.test(file)
4+
5+
export const isCSS = (file: string): boolean => /\.css($|\?)/.test(file)

src/server/webpack-plugin/client.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -15,20 +15,20 @@ export default class VueSSRClientPlugin {
1515
const allFiles = stats.assets
1616
.map(a => a.name)
1717

18-
const initialScripts = Object.keys(stats.entrypoints)
18+
const initialFiles = Object.keys(stats.entrypoints)
1919
.map(name => stats.entrypoints[name].assets)
2020
.reduce((assets, all) => all.concat(assets), [])
2121
.filter(isJS)
2222

23-
const asyncScripts = allFiles
23+
const asyncFiles = allFiles
2424
.filter(isJS)
25-
.filter(file => initialScripts.indexOf(file) < 0)
25+
.filter(file => initialFiles.indexOf(file) < 0)
2626

2727
const manifest = {
2828
publicPath: stats.publicPath,
2929
all: allFiles,
30-
initial: initialScripts,
31-
async: asyncScripts,
30+
initial: initialFiles,
31+
async: asyncFiles,
3232
modules: { /* [identifier: string]: Array<index: number> */ }
3333
}
3434

src/server/webpack-plugin/util.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,4 @@ export const validate = compiler => {
2121
}
2222
}
2323

24-
export const isJS = file => /\.js($|\?)/.test(file)
24+
export { isJS, isCSS } from '../util'

test/ssr/compile-with-webpack.js

+1-1
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ export function compileWithWebpack (file, extraConfig, cb) {
1616
loader: require.resolve('./async-loader')
1717
},
1818
{
19-
test: /\.(png|woff2)$/,
19+
test: /\.(png|woff2|css)$/,
2020
loader: 'file-loader',
2121
options: {
2222
name: '[name].[ext]'

test/ssr/fixtures/async-foo.js

+1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
// import image and font
2+
import './test.css'
23
import font from './test.woff2'
34
import image from './test.png'
45

test/ssr/fixtures/test.css

Whitespace-only changes.

test/ssr/ssr-template.spec.js

+8-4
Original file line numberDiff line numberDiff line change
@@ -225,11 +225,14 @@ describe('SSR: template option', () => {
225225
`<link rel="preload" href="/manifest.js" as="script">` +
226226
`<link rel="preload" href="/main.js" as="script">` +
227227
`<link rel="preload" href="/0.js" as="script">` +
228+
`<link rel="preload" href="/test.css" as="style">` +
228229
// images and fonts are only preloaded when explicitly asked for
229230
(preloadOtherAssets ? `<link rel="preload" href="/test.png" as="image">` : ``) +
230231
(preloadOtherAssets ? `<link rel="preload" href="/test.woff2" as="font" type="font/woff2" crossorigin>` : ``) +
231232
// unused chunks should have prefetch
232233
`<link rel="prefetch" href="/1.js" as="script">` +
234+
// css assets should be loaded
235+
`<link rel="stylesheet" href="/test.css">` +
233236
`</head><body>` +
234237
`<div data-server-rendered="true"><div>async test.woff2 test.png</div></div>` +
235238
// manifest chunk should be first
@@ -243,7 +246,7 @@ describe('SSR: template option', () => {
243246
createClientManifestAssertions(false)
244247

245248
function createClientManifestAssertions (runInNewContext) {
246-
it('bundleRenderer + renderToString + clientManifest', done => {
249+
it('bundleRenderer + renderToString + clientManifest ()', done => {
247250
createRendererWithManifest('split.js', { runInNewContext }, renderer => {
248251
renderer.renderToString({}, (err, res) => {
249252
expect(err).toBeNull()
@@ -257,7 +260,7 @@ describe('SSR: template option', () => {
257260
createRendererWithManifest('split.js', {
258261
runInNewContext,
259262
shouldPreload: (file, type) => {
260-
if (type === 'image' || type === 'script' || type === 'font') {
263+
if (type === 'image' || type === 'script' || type === 'font' || type === 'style') {
261264
return true
262265
}
263266
}
@@ -278,7 +281,7 @@ describe('SSR: template option', () => {
278281
createRendererWithManifest('split.js', {
279282
runInNewContext,
280283
template: `<html>` +
281-
`<head>{{{ renderResourceHints() }}}</head>` +
284+
`<head>{{{ renderResourceHints() }}}{{{ renderStyles() }}}</head>` +
282285
`<body><!--vue-ssr-outlet-->{{{ renderScripts() }}}</body>` +
283286
`</html>`,
284287
inject: false
@@ -303,7 +306,8 @@ describe('SSR: template option', () => {
303306

304307
const customOutput =
305308
`<html><head>${
306-
context.renderResourceHints()
309+
context.renderResourceHints() +
310+
context.renderStyles()
307311
}</head><body>${
308312
res +
309313
context.renderScripts()

0 commit comments

Comments
 (0)