UNPKG

4.56 kBJavaScriptView Raw
1const path = require('path')
2const fs = require('fs-extra')
3
4exports.name = 'vue-static'
5
6exports.apply = (api, { staticRoutes, resourceHints = true } = {}) => {
7 if (
8 !api.hasDependency('vue') ||
9 !api.hasDependency('vue-template-compiler')
10 ) {
11 throw new api.PoiError({
12 message: `You must have both "vue" and "vue-template-compiler" installed in your project`
13 })
14 }
15
16 api.hook('createConfig', config => {
17 if (!Array.isArray(config.entry) && typeof config.entry === 'object') {
18 throw new api.PoiError({
19 message: `When using plugin vue-static, the value of \`entry\` option cannot be an object`
20 })
21 }
22
23 if (Array.isArray(config.entry) && config.entry.length > 1) {
24 api.logger.warn(
25 `\`entry\` is an array, however we only use the first item in vue-static plugin`
26 )
27 }
28
29 config.babel.jsx = 'vue'
30 })
31
32 api.hook('createWebpackChain', (config, { type }) => {
33 // Remove the entry added by Poi core
34 config.entryPoints.clear()
35 // And instead add our own entries
36 config.entry('index').add(path.join(__dirname, `app/entry-${type}.js`))
37 // Set the user entry as an alias so that we can reference it in app code
38 config.resolve.alias.set(
39 '#user-entry$',
40 api.resolveCwd(
41 Array.isArray(api.config.entry) ? api.config.entry[0] : api.config.entry
42 )
43 )
44 // Output files to a temp directory
45 config.output.path(api.resolveCwd(`.vue-static/${type}`))
46
47 // Add vue ssr plugin
48 config.plugin('vue-ssr').use(require(`vue-server-renderer/${type}-plugin`))
49
50 config.module.rule('js').include.add(path.join(__dirname, 'app'))
51
52 if (type === 'server') {
53 config.output.libraryTarget('commonjs2')
54 config.target('node')
55 const externals = config.get('externals')
56 config.externals(
57 [
58 require('webpack-node-externals')({
59 whitelist: [/\.(?!(?:jsx?|json)$).{1,5}$/i]
60 })
61 ].concat(externals || [])
62 )
63 config.optimization.splitChunks(false)
64 config.optimization.runtimeChunk(false)
65 }
66
67 if (!api.cli.options.serve) {
68 config
69 .plugin('html')
70 .tap(([options]) => [
71 Object.assign(options, { inject: false, minify: false })
72 ])
73 }
74
75 config.plugin('constants').tap(([options]) => [
76 Object.assign({}, options, {
77 'process.server': type === 'server',
78 'process.browser': type === 'client',
79 'process.client': type === 'client'
80 })
81 ])
82
83 config.plugin('print-status').tap(([options]) => [
84 Object.assign(options, {
85 printFileStats: false
86 })
87 ])
88 })
89
90 api.hook('createCLI', ({ command }) => {
91 // Override the action for default command
92 const defaultAction = command.commandAction
93 command.action(async (...args) => {
94 if (api.cli.options.serve) {
95 // Use default action under --serve
96 // It will be served as a normal SPA
97 await defaultAction(...args)
98 } else {
99 // Generate two builds otherwise
100 // And use them to generate static HTML files with vue-server-renderer
101 const clientConfig = api
102 .createWebpackChain({ type: 'client' })
103 .toConfig()
104 const serverConfig = api
105 .createWebpackChain({ type: 'server' })
106 .toConfig()
107 const [clientStats, serverStats] = await Promise.all([
108 api.runCompiler(api.createWebpackCompiler(clientConfig)),
109 api.runCompiler(api.createWebpackCompiler(serverConfig))
110 ])
111 if (clientStats.hasErrors() || serverStats.hasErrors()) {
112 return
113 }
114 await fs.copy(api.resolveCwd(`.vue-static/client`), api.resolveOutDir())
115 await require('./generate')(api, {
116 serverBundle: require(api.resolveCwd(
117 '.vue-static/server/vue-ssr-server-bundle.json'
118 )),
119 clientManifest: require(api.resolveCwd(
120 '.vue-static/client/vue-ssr-client-manifest.json'
121 )),
122 staticRoutes,
123 resourceHints,
124 htmlSkeletion: await fs.readFile(
125 api.resolveCwd('.vue-static/client/index.html'),
126 'utf8'
127 )
128 })
129 await Promise.all([
130 fs.remove(api.resolveCwd('.vue-static')),
131 fs.remove(api.resolveOutDir('vue-ssr-client-manifest.json'))
132 ])
133 api.logger.done(
134 `Successfully generated into ${path.relative(
135 process.cwd(),
136 api.resolveOutDir()
137 )}`
138 )
139 }
140 })
141 })
142}