Skip to content

Commit bb2db70

Browse files
Andrés AlvarezAndrés Alvarez
authored andcommitted
feat(packages/sui-ssr): add ssr dev mode
1 parent 99e46ad commit bb2db70

File tree

3 files changed

+162
-3
lines changed

3 files changed

+162
-3
lines changed

packages/sui-ssr/bin/sui-ssr-dev.js

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
1+
#!/usr/bin/env node
2+
/* eslint-disable no-console */
3+
4+
const {WEBPACK_PORT = 8080} = process.env
5+
process.env.CDN = `http://localhost:${WEBPACK_PORT}/`
6+
7+
const program = require('commander')
8+
const {exec} = require('child_process')
9+
const path = require('path')
10+
const fs = require('fs')
11+
const express = require('express')
12+
const webpack = require('webpack')
13+
const webpackDevMiddleware = require('webpack-dev-middleware')
14+
const webpackHotMiddleware = require('webpack-hot-middleware')
15+
const nodemon = require('nodemon')
16+
const clientConfig = require('@s-ui/bundler/webpack.config.server.dev.js')
17+
const linkLoaderConfigBuilder = require('@s-ui/bundler/loaders/linkLoaderConfigBuilder.js')
18+
19+
const serverConfigFactory = require('../compiler/server.js')
20+
21+
const SERVER_OUTPUT_PATH = path.join(process.cwd(), '.sui/server')
22+
const STATICS_OUTPUT_PATH = path.join(process.cwd(), '.sui/statics')
23+
const STATICS_PATH = path.join(process.cwd(), './statics')
24+
25+
program
26+
.option('-L, --link-all [monorepo]', 'Link all packages inside of monorepo multipackage')
27+
.option(
28+
'-l, --link-package [package]',
29+
'Replace each occurrence of this package with an absolute path to this folder',
30+
(v, m) => {
31+
m.push(v)
32+
return m
33+
},
34+
[]
35+
)
36+
.parse(process.argv)
37+
38+
const compile = (name, compiler) => {
39+
return new Promise((resolve, reject) => {
40+
compiler.hooks.compile.tap(name, () => {
41+
console.time(`[${name}] Compiling`)
42+
})
43+
compiler.hooks.done.tap(name, stats => {
44+
console.timeEnd(`[${name}] Compiling`)
45+
if (!stats.hasErrors()) {
46+
return resolve()
47+
}
48+
return reject(new Error(`Failed to compile ${name}`))
49+
})
50+
})
51+
}
52+
53+
const linkStatics = () => {
54+
return new Promise((resolve, reject) =>
55+
fs.symlink(STATICS_PATH, STATICS_OUTPUT_PATH, 'dir', err => {
56+
if (err) {
57+
if (err.code === 'EEXIST') {
58+
return resolve()
59+
}
60+
61+
return reject(err)
62+
}
63+
64+
resolve()
65+
})
66+
)
67+
}
68+
69+
const initMSW = () => {
70+
return exec(`npx msw init ${STATICS_PATH}`)
71+
}
72+
73+
const start = ({packagesToLink, linkAll}) => {
74+
const app = express()
75+
const clientCompiler = webpack(
76+
linkLoaderConfigBuilder({
77+
config: require('@s-ui/bundler/webpack.config.server.dev.js'),
78+
linkAll,
79+
packagesToLink
80+
})
81+
)
82+
const serverCompiler = webpack(
83+
linkLoaderConfigBuilder({
84+
config: serverConfigFactory({outputPath: SERVER_OUTPUT_PATH}),
85+
linkAll,
86+
packagesToLink
87+
})
88+
)
89+
const watchOptions = {
90+
ignored: /node_modules/,
91+
stats: clientConfig.stats
92+
}
93+
94+
app.use((_req, res, next) => {
95+
res.header('Access-Control-Allow-Origin', '*')
96+
return next()
97+
})
98+
99+
app.use(
100+
webpackDevMiddleware(clientCompiler, {
101+
publicPath: clientConfig.output.publicPath,
102+
stats: clientConfig.stats,
103+
writeToDisk: true
104+
})
105+
)
106+
app.use(webpackHotMiddleware(clientCompiler))
107+
108+
app.listen(WEBPACK_PORT)
109+
110+
serverCompiler.watch(watchOptions, (error, stats) => {
111+
if (!error && !stats.hasErrors()) {
112+
return
113+
}
114+
115+
if (error) {
116+
console.log(error, 'error')
117+
}
118+
119+
if (stats.hasErrors()) {
120+
const info = stats.toJson()
121+
const errors = info.errors
122+
123+
console.log(errors)
124+
}
125+
})
126+
127+
Promise.all([linkStatics(), initMSW(), compile('client', clientCompiler), compile('server', serverCompiler)])
128+
.then(() => {
129+
const script = nodemon({
130+
script: `${SERVER_OUTPUT_PATH}/index.js`,
131+
watch: [SERVER_OUTPUT_PATH],
132+
delay: 200
133+
})
134+
135+
script.on('restart', () => {
136+
console.log('Server side app has been restarted.', 'warning')
137+
})
138+
139+
script.on('quit', () => {
140+
console.log('Process ended')
141+
process.exit()
142+
})
143+
144+
script.on('error', () => {
145+
console.log('An error occured. Exiting', 'error')
146+
process.exit(1)
147+
})
148+
})
149+
.catch(error => {
150+
console.log('error', error)
151+
})
152+
}
153+
const opts = program.opts()
154+
155+
start({packagesToLink: opts.linkPackage, linkAll: opts.linkAll})

packages/sui-ssr/package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,9 @@
3737
"mime": "1.6.0",
3838
"noop-console": "0.8.0",
3939
"parse5": "6.0.1",
40-
"ua-parser-js": "0.7.33"
40+
"ua-parser-js": "0.7.33",
41+
"webpack-dev-middleware": "6.1.1",
42+
"webpack-hot-middleware": "2.25.4",
43+
"nodemon": "3.0.1"
4144
}
4245
}

packages/sui-ssr/server/utils/factory.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
1+
const IS_PRODUCTION = process.env.NODE_ENV === 'production'
12
const DEFAULT_SITE_HEADER = 'X-Serve-Site'
2-
const DEFAULT_PUBLIC_FOLDER = 'public'
3+
const DEFAULT_PUBLIC_FOLDER = IS_PRODUCTION ? 'public' : '.sui/public'
34
const DEFAULT_MULTI_SITE_KEY = 'default'
45
const EXPRESS_STATIC_CONFIG = {index: false}
56

@@ -29,7 +30,7 @@ export default ({path, fs, config: ssrConf = {}, assetsManifest}) => {
2930

3031
const publicFolder = req => {
3132
const site = siteByHost(req)
32-
if (!site) return DEFAULT_PUBLIC_FOLDER
33+
if (!site || !IS_PRODUCTION) return DEFAULT_PUBLIC_FOLDER
3334

3435
return multiSitePublicFolder(site)
3536
}

0 commit comments

Comments
 (0)