Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
N
node-sample
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
周韬
node-sample
Commits
402e1090
Commit
402e1090
authored
Mar 27, 2017
by
Evan You
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
update setup to leverage client preloading
parent
1c85abcd
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
46 additions
and
137 deletions
+46
-137
setup-dev-server.js
build/setup-dev-server.js
+22
-11
webpack.client.config.js
build/webpack.client.config.js
+7
-7
webpack.server.config.js
build/webpack.server.config.js
+2
-2
mapFiles.js
mapFiles.js
+0
-64
server.js
server.js
+13
-51
entry-client.js
src/entry-client.js
+1
-1
entry-server.js
src/entry-server.js
+1
-1
No files found.
build/setup-dev-server.js
View file @
402e1090
...
...
@@ -5,8 +5,7 @@ const clientConfig = require('./webpack.client.config')
const
serverConfig
=
require
(
'./webpack.server.config'
)
module
.
exports
=
function
setupDevServer
(
app
,
cb
)
{
let
bundle
let
template
let
bundle
,
template
,
serverManifest
,
clientManifest
// modify client config to work with hot middleware
clientConfig
.
entry
.
app
=
[
'webpack-hot-middleware/client'
,
clientConfig
.
entry
.
app
]
...
...
@@ -25,12 +24,17 @@ module.exports = function setupDevServer (app, cb) {
app
.
use
(
devMiddleware
)
clientCompiler
.
plugin
(
'done'
,
()
=>
{
const
fs
=
devMiddleware
.
fileSystem
const
filePath
=
path
.
join
(
clientConfig
.
output
.
path
,
'index.html'
)
if
(
fs
.
existsSync
(
filePath
))
{
template
=
fs
.
readFileSync
(
filePath
,
'utf-8'
)
if
(
bundle
)
{
cb
(
bundle
,
template
)
const
readFile
=
file
=>
fs
.
readFileSync
(
path
.
join
(
clientConfig
.
output
.
path
,
file
),
'utf-8'
)
template
=
readFile
(
'index.html'
)
clientManifest
=
JSON
.
parse
(
readFile
(
'vue-ssr-manifest-client.json'
))
if
(
bundle
&&
serverManifest
)
{
cb
(
bundle
,
{
template
,
manifest
:
{
server
:
serverManifest
,
client
:
clientManifest
}
})
}
})
...
...
@@ -46,12 +50,19 @@ module.exports = function setupDevServer (app, cb) {
stats
=
stats
.
toJson
()
stats
.
errors
.
forEach
(
err
=>
console
.
error
(
err
))
stats
.
warnings
.
forEach
(
err
=>
console
.
warn
(
err
))
const
readFile
=
file
=>
mfs
.
readFileSync
(
path
.
join
(
clientConfig
.
output
.
path
,
file
),
'utf-8'
)
// read bundle generated by vue-ssr-webpack-plugin
const
bundlePath
=
path
.
join
(
serverConfig
.
output
.
path
,
'vue-ssr-bundle.json'
)
bundle
=
JSON
.
parse
(
mfs
.
readFileSync
(
bundlePath
,
'utf-8'
))
if
(
template
)
{
cb
(
bundle
,
template
)
bundle
=
JSON
.
parse
(
readFile
(
'vue-ssr-bundle.json'
))
serverManifest
=
JSON
.
parse
(
readFile
(
'vue-ssr-manifest-server.json'
))
if
(
template
&&
clientManifest
)
{
cb
(
bundle
,
{
template
,
manifest
:
{
server
:
serverManifest
,
client
:
clientManifest
}
})
}
})
}
build/webpack.client.config.js
View file @
402e1090
...
...
@@ -4,7 +4,7 @@ const base = require('./webpack.base.config')
const
vueConfig
=
require
(
'./vue-loader.config'
)
const
HTMLPlugin
=
require
(
'html-webpack-plugin'
)
const
SWPrecachePlugin
=
require
(
'sw-precache-webpack-plugin'
)
const
VueSSRPlugin
=
require
(
'vue-ssr-webpack-plugin'
).
client
const
VueSSR
Client
Plugin
=
require
(
'vue-ssr-webpack-plugin'
).
client
const
config
=
merge
(
base
,
{
entry
:
'./src/entry-client.js'
,
...
...
@@ -36,18 +36,18 @@ const config = merge(base, {
new
HTMLPlugin
({
template
:
'src/index.template.html'
}),
new
VueSSRPlugin
()
new
VueSSR
Client
Plugin
()
]
})
if
(
process
.
env
.
NODE_ENV
===
'production'
)
{
config
.
plugins
.
push
(
// minify JS
//
new webpack.optimize.UglifyJsPlugin({
//
compress: {
//
warnings: false
//
}
//
}),
new
webpack
.
optimize
.
UglifyJsPlugin
({
compress
:
{
warnings
:
false
}
}),
// auto generate service worker
new
SWPrecachePlugin
({
cacheId
:
'vue-hn'
,
...
...
build/webpack.server.config.js
View file @
402e1090
const
webpack
=
require
(
'webpack'
)
const
merge
=
require
(
'webpack-merge'
)
const
base
=
require
(
'./webpack.base.config'
)
const
VueSSRPlugin
=
require
(
'vue-ssr-webpack-plugin'
).
server
const
VueSSR
Server
Plugin
=
require
(
'vue-ssr-webpack-plugin'
).
server
module
.
exports
=
merge
(
base
,
{
target
:
'node'
,
...
...
@@ -22,6 +22,6 @@ module.exports = merge(base, {
'process.env.NODE_ENV'
:
JSON
.
stringify
(
process
.
env
.
NODE_ENV
||
'development'
),
'process.env.VUE_ENV'
:
'"server"'
}),
new
VueSSRPlugin
()
new
VueSSR
Server
Plugin
()
]
})
mapFiles.js
deleted
100644 → 0
View file @
1c85abcd
module
.
exports
=
function
createMapper
(
serverStats
,
clientStats
)
{
const
fileMap
=
createFileMap
(
serverStats
,
clientStats
)
return
function
mapFiles
(
files
)
{
const
res
=
new
Set
()
for
(
let
i
=
0
;
i
<
files
.
length
;
i
++
)
{
const
mapped
=
fileMap
.
get
(
files
[
i
])
for
(
let
j
=
0
;
j
<
mapped
.
length
;
j
++
)
{
res
.
add
(
mapped
[
j
])
}
}
return
Array
.
from
(
res
)
}
}
function
createFileMap
(
serverStats
,
clientStats
)
{
const
fileMap
=
new
Map
()
serverStats
.
assets
.
filter
(
asset
=>
/
\.
js$/
.
test
(
asset
.
name
))
.
forEach
(
asset
=>
fileMap
.
set
(
asset
.
name
,
mapFile
(
asset
.
name
,
serverStats
,
clientStats
)))
return
fileMap
}
function
mapFile
(
file
,
serverStats
,
clientStats
)
{
// 1. server files -> server chunk ids
const
serverChunkIds
=
new
Set
()
serverStats
.
assets
.
forEach
(
asset
=>
{
if
(
asset
.
name
===
file
)
{
asset
.
chunks
.
forEach
(
id
=>
{
const
chunk
=
serverStats
.
chunks
.
find
(
c
=>
c
.
id
===
id
)
if
(
!
chunk
.
initial
)
{
serverChunkIds
.
add
(
id
)
}
})
}
})
// 2. server chunks -> module identifiers
const
moduleIdentifiers
=
[]
serverStats
.
modules
.
forEach
(
module
=>
{
if
(
module
.
chunks
.
some
(
id
=>
serverChunkIds
.
has
(
id
)))
{
moduleIdentifiers
.
push
(
module
.
identifier
)
}
})
// 3. module identifiers -> client chunk ids
const
clientChunkIds
=
new
Set
()
moduleIdentifiers
.
forEach
(
identifier
=>
{
const
clientModule
=
clientStats
.
modules
.
find
(
m
=>
m
.
identifier
===
identifier
)
if
(
clientModule
&&
clientModule
.
chunks
.
length
===
1
)
{
// ignore modules duplicated in multiple chunks
clientChunkIds
.
add
(
clientModule
.
chunks
[
0
])
}
})
// 4. client chunks -> client files
const
clientFiles
=
new
Set
()
Array
.
from
(
clientChunkIds
).
forEach
(
id
=>
{
const
chunk
=
clientStats
.
chunks
.
find
(
chunk
=>
chunk
.
id
===
id
)
if
(
!
chunk
.
initial
)
{
chunk
.
files
.
forEach
(
file
=>
clientFiles
.
add
(
file
))
}
})
return
Array
.
from
(
clientFiles
)
}
server.js
View file @
402e1090
...
...
@@ -3,28 +3,8 @@ const path = require('path')
const
express
=
require
(
'express'
)
const
favicon
=
require
(
'serve-favicon'
)
const
compression
=
require
(
'compression'
)
const
createFileMapper
=
require
(
'./mapFiles'
)
const
resolve
=
file
=>
path
.
resolve
(
__dirname
,
file
)
const
serverStats
=
require
(
'./dist/server-stats.json'
)
const
clientStats
=
require
(
'./dist/client-stats.json'
)
const
clientInitialFiles
=
[]
const
clientAsyncFiles
=
[]
clientStats
.
chunks
.
forEach
(
chunk
=>
{
chunk
.
files
.
forEach
(
file
=>
{
if
(
chunk
.
initial
)
{
clientInitialFiles
.
push
(
file
)
}
else
{
clientAsyncFiles
.
push
(
file
)
}
})
})
const
clientInitialFileLinks
=
clientInitialFiles
.
map
(
file
=>
{
return
`<link rel="preload" href="/dist/
${
file
}
" as="
${
/
\
.
css$
/
.
test
(
file
)
?
'style'
:
'script'
}
">`
}).
join
(
''
)
const
isProd
=
process
.
env
.
NODE_ENV
===
'production'
const
serverInfo
=
`express/
${
require
(
'express/package.json'
).
version
}
`
+
...
...
@@ -32,7 +12,7 @@ const serverInfo =
const
app
=
express
()
let
renderer
,
mapFiles
let
renderer
if
(
isProd
)
{
// In production: create server renderer using server bundle and index HTML
// template from real fs.
...
...
@@ -41,26 +21,29 @@ if (isProd) {
// src/index.template.html is processed by html-webpack-plugin to inject
// build assets and output as dist/index.html.
const
template
=
fs
.
readFileSync
(
resolve
(
'./dist/index.html'
),
'utf-8'
)
mapFiles
=
createFileMapper
(
serverStats
,
clientStats
)
renderer
=
createRenderer
(
bundle
,
template
)
renderer
=
createRenderer
(
bundle
,
{
template
,
manifest
:
{
server
:
require
(
'./dist/vue-ssr-manifest-server.json'
),
client
:
require
(
'./dist/vue-ssr-manifest-client.json'
)
}
})
}
else
{
mapFiles
=
()
=>
[]
// In development: setup the dev server with watch and hot-reload,
// and create a new renderer on bundle / index template update.
require
(
'./build/setup-dev-server'
)(
app
,
(
bundle
,
template
)
=>
{
renderer
=
createRenderer
(
bundle
,
template
)
require
(
'./build/setup-dev-server'
)(
app
,
(
bundle
,
options
)
=>
{
renderer
=
createRenderer
(
bundle
,
options
)
})
}
function
createRenderer
(
bundle
,
template
)
{
function
createRenderer
(
bundle
,
options
)
{
// https://github.com/vuejs/vue/blob/dev/packages/vue-server-renderer/README.md#why-use-bundlerenderer
return
require
(
'vue-server-renderer'
).
createBundleRenderer
(
bundle
,
{
template
,
return
require
(
'vue-server-renderer'
).
createBundleRenderer
(
bundle
,
Object
.
assign
(
options
,
{
cache
:
require
(
'lru-cache'
)({
max
:
1000
,
maxAge
:
1000
*
60
*
15
})
})
})
)
}
const
serve
=
(
path
,
cache
)
=>
express
.
static
(
resolve
(
path
),
{
...
...
@@ -98,27 +81,6 @@ app.get('*', (req, res) => {
const
context
=
{
url
:
req
.
url
}
renderer
.
renderToStream
(
context
)
.
on
(
'error'
,
errorHandler
)
.
on
(
'beforeStart'
,
()
=>
{
// load the needed async chunk
const
usedFiles
=
Object
.
keys
(
context
.
_evaluatedFiles
)
const
neededFiles
=
mapFiles
(
usedFiles
)
context
.
asyncChunks
=
neededFiles
.
map
(
file
=>
{
return
`<script src="/dist/
${
file
}
"></script>`
}).
join
(
''
)
// preload initial chunks
context
.
head
=
(
context
.
head
||
''
)
+
clientInitialFileLinks
// prefetch async chunks
const
laterFiles
=
clientAsyncFiles
.
map
(
file
=>
{
if
(
neededFiles
.
indexOf
(
file
)
<
0
)
{
return
`<link rel="prefetch" href="/dist/
${
file
}
" as="script">`
}
else
{
return
''
}
}).
join
(
''
)
context
.
head
+=
laterFiles
})
.
on
(
'end'
,
()
=>
console
.
log
(
`whole request:
${
Date
.
now
()
-
s
}
ms`
))
.
pipe
(
res
)
})
...
...
src/entry-client.js
View file @
402e1090
...
...
@@ -16,5 +16,5 @@ router.onReady(() => {
// service worker
if
(
process
.
env
.
NODE_ENV
===
'production'
&&
'serviceWorker'
in
navigator
)
{
//
navigator.serviceWorker.register('/service-worker.js')
navigator
.
serviceWorker
.
register
(
'/service-worker.js'
)
}
src/entry-server.js
View file @
402e1090
...
...
@@ -26,7 +26,7 @@ export default context => {
// which is resolved when the action is complete and store state has been
// updated.
Promise
.
all
(
matchedComponents
.
map
(
component
=>
{
//
return component.preFetch && component.preFetch(store)
return
component
.
preFetch
&&
component
.
preFetch
(
store
)
})).
then
(()
=>
{
isDev
&&
console
.
log
(
`data pre-fetch:
${
Date
.
now
()
-
s
}
ms`
)
// After all preFetch hooks are resolved, our store is now
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment