@@ -7,104 +7,147 @@ const MiniCssExtractPlugin = require('mini-css-extract-plugin')
7
7
8
8
module . exports = ( env = { } ) => {
9
9
const isProd = env . prod
10
- const minimize = isProd && ! env . noMinimize
11
- const babel = isProd && ! env . noBabel
10
+ const isSSR = env . ssr
12
11
13
- return {
14
- mode : isProd ? 'production' : 'development' ,
15
- entry : path . resolve ( __dirname , './main.js' ) ,
16
- devtool : 'source-map' ,
17
- output : {
18
- path : path . resolve ( __dirname , 'dist' ) ,
19
- filename : '[name].js' ,
20
- publicPath : '/dist/' ,
21
- } ,
22
- module : {
23
- rules : [
24
- {
25
- test : / \. v u e $ / ,
26
- loader : 'vue-loader' ,
27
- } ,
28
- {
29
- test : / \. p n g $ / ,
30
- use : [
31
- {
32
- loader : 'url-loader' ,
33
- options : {
34
- limit : 8192 ,
35
- } ,
12
+ /**
13
+ * Some notes regarding config for the server build of an SSR app:
14
+ * 1. target: 'node'
15
+ * 2. output.libraryTarget: 'commonjs' (so the exported app can be required)
16
+ * 3. externals: this is mostly for faster builds.
17
+ * - externalize @vue/* deps via commonjs require()
18
+ * - externalize client side deps that are never used on the server, e.g.
19
+ * ones that are only used in onMounted() to empty modules
20
+ * 4. If using cache-loader or any other forms of cache, make sure the cache
21
+ * key takes client vs. server builds into account!
22
+ */
23
+ const genConfig = ( isServerBuild = false ) => {
24
+ const minimize = isProd && ! isServerBuild && ! env . noMinimize
25
+ const useBabel = isProd && ! isServerBuild && ! env . noBabel
26
+
27
+ return {
28
+ mode : isProd ? 'production' : 'development' ,
29
+ entry : path . resolve ( __dirname , './main.js' ) ,
30
+ target : isServerBuild ? 'node' : 'web' ,
31
+ devtool : 'source-map' ,
32
+ output : {
33
+ path : path . resolve (
34
+ __dirname ,
35
+ isSSR ? ( isServerBuild ? 'dist-ssr/server' : 'dist-ssr/dist' ) : 'dist'
36
+ ) ,
37
+ filename : '[name].js' ,
38
+ publicPath : '/dist/' ,
39
+ libraryTarget : isServerBuild ? 'commonjs' : undefined ,
40
+ } ,
41
+ externals : isServerBuild
42
+ ? [
43
+ ( ctx , request , cb ) => {
44
+ if ( / ^ @ v u e / . test ( request ) ) {
45
+ return cb ( null , 'commonjs ' + request )
46
+ }
47
+ cb ( )
36
48
} ,
37
- ] ,
38
- } ,
39
- {
40
- test : / \. c s s $ / ,
41
- use : [
42
- {
43
- loader : MiniCssExtractPlugin . loader ,
44
- options : {
45
- hmr : ! isProd ,
49
+ ]
50
+ : undefined ,
51
+ module : {
52
+ rules : [
53
+ {
54
+ test : / \. v u e $ / ,
55
+ loader : 'vue-loader' ,
56
+ } ,
57
+ {
58
+ test : / \. p n g $ / ,
59
+ use : [
60
+ {
61
+ loader : 'url-loader' ,
62
+ options : {
63
+ limit : 8192 ,
64
+ } ,
46
65
} ,
47
- } ,
48
- 'css-loader' ,
49
- ] ,
50
- } ,
51
- {
52
- test : / \. j s $ / ,
53
- use : [
54
- {
55
- loader : 'cache-loader' ,
56
- options : {
57
- cacheIdentifier : hash (
58
- fs . readFileSync ( path . resolve ( __dirname , '../package.json' ) ) +
59
- JSON . stringify ( env )
60
- ) ,
61
- cacheDirectory : path . resolve ( __dirname , '../.cache' ) ,
66
+ ] ,
67
+ } ,
68
+ {
69
+ test : / \. c s s $ / ,
70
+ use : [
71
+ {
72
+ loader : MiniCssExtractPlugin . loader ,
73
+ options : {
74
+ hmr : ! isProd ,
75
+ } ,
62
76
} ,
63
- } ,
64
- ...( babel
65
- ? [
66
- {
67
- loader : 'babel-loader' ,
68
- options : {
69
- // use yarn build-example --env.noMinimize to verify that
70
- // babel is properly applied to all js code, including the
71
- // render function compiled from SFC templates.
72
- presets : [ '@babel/preset-env' ] ,
77
+ 'css-loader' ,
78
+ ] ,
79
+ } ,
80
+ {
81
+ test : / \. j s $ / ,
82
+ use : [
83
+ {
84
+ loader : 'cache-loader' ,
85
+ options : {
86
+ cacheIdentifier : hash (
87
+ // deps
88
+ fs . readFileSync (
89
+ path . resolve ( __dirname , '../package.json' )
90
+ ) +
91
+ // env
92
+ JSON . stringify ( env ) +
93
+ // client vs. server build
94
+ isServerBuild
95
+ ) ,
96
+ cacheDirectory : path . resolve ( __dirname , '../.cache' ) ,
97
+ } ,
98
+ } ,
99
+ ...( useBabel
100
+ ? [
101
+ {
102
+ loader : 'babel-loader' ,
103
+ options : {
104
+ // use yarn build-example --env.noMinimize to verify that
105
+ // babel is properly applied to all js code, including the
106
+ // render function compiled from SFC templates.
107
+ presets : [ '@babel/preset-env' ] ,
108
+ } ,
73
109
} ,
74
- } ,
75
- ]
76
- : [ ] ) ,
77
- ] ,
78
- } ,
79
- // target <docs> custom blocks
80
- {
81
- resourceQuery : / b l o c k T y p e = d o c s / ,
82
- loader : require . resolve ( './docs-loader' ) ,
83
- } ,
110
+ ]
111
+ : [ ] ) ,
112
+ ] ,
113
+ } ,
114
+ // target <docs> custom blocks
115
+ {
116
+ resourceQuery : / b l o c k T y p e = d o c s / ,
117
+ loader : require . resolve ( './docs-loader' ) ,
118
+ } ,
119
+ ] ,
120
+ } ,
121
+ plugins : [
122
+ new VueLoaderPlugin ( ) ,
123
+ new MiniCssExtractPlugin ( {
124
+ filename : '[name].css' ,
125
+ } ) ,
126
+ new webpack . DefinePlugin ( {
127
+ __IS_SSR__ : ! ! isSSR ,
128
+ __VUE_OPTIONS_API__ : true ,
129
+ __VUE_PROD_DEVTOOLS__ : false ,
130
+ } ) ,
84
131
] ,
85
- } ,
86
- plugins : [
87
- new VueLoaderPlugin ( ) ,
88
- new MiniCssExtractPlugin ( {
89
- filename : '[name].css' ,
90
- } ) ,
91
- new webpack . DefinePlugin ( {
92
- __VUE_OPTIONS_API__ : true ,
93
- __VUE_PROD_DEVTOOLS__ : false ,
94
- } ) ,
95
- ] ,
96
- optimization : {
97
- minimize,
98
- } ,
99
- devServer : {
100
- stats : 'minimal' ,
101
- contentBase : __dirname ,
102
- overlay : true ,
103
- } ,
104
- resolveLoader : {
105
- alias : {
106
- 'vue-loader' : require . resolve ( '../' ) ,
132
+ optimization : {
133
+ minimize,
134
+ } ,
135
+ devServer : {
136
+ stats : 'minimal' ,
137
+ contentBase : __dirname ,
138
+ overlay : true ,
107
139
} ,
108
- } ,
140
+ resolveLoader : {
141
+ alias : {
142
+ 'vue-loader' : require . resolve ( '../' ) ,
143
+ } ,
144
+ } ,
145
+ }
146
+ }
147
+
148
+ if ( ! isSSR ) {
149
+ return genConfig ( )
150
+ } else {
151
+ return [ genConfig ( ) , genConfig ( true ) ]
109
152
}
110
153
}
0 commit comments