1 | exports.name = 'builtin:serve'
|
2 |
|
3 | exports.apply = api => {
|
4 | api.hook('createCLI', ({ command, args }) => {
|
5 | command.option('-s, --serve', 'Serve assets on a local server')
|
6 |
|
7 | if (!args.has('s') && !args.has('serve')) return
|
8 |
|
9 | command
|
10 | .option('-p, --port <port>', 'Server port', { default: '4000' })
|
11 | .option('--host <host>', 'Server host', { default: '0.0.0.0' })
|
12 | .option('--proxy <url>', 'Proxy API requests')
|
13 | .option('--no-hot', 'Disable hot reloading')
|
14 | .option('-o, --open', 'Open in browser')
|
15 |
|
16 | command.action(async () => {
|
17 | const devServer = Object.assign({}, api.config.devServer)
|
18 | delete devServer.hotEntries
|
19 |
|
20 | const { host, port: _port, open } = devServer
|
21 | const port = await require('get-port')({ port: _port })
|
22 |
|
23 | const webpackConfig = api.createWebpackChain().toConfig()
|
24 |
|
25 |
|
26 | if (api.mode !== 'test') {
|
27 | webpackConfig.plugins.push({
|
28 | apply(compiler) {
|
29 |
|
30 | compiler.hooks.done.tap('print-serve-urls', stats => {
|
31 | if (stats.hasErrors() || stats.hasWarnings()) return
|
32 |
|
33 | require('@poi/dev-utils/printServeMessage')({
|
34 | host,
|
35 | port,
|
36 | open
|
37 | })
|
38 | })
|
39 | }
|
40 | })
|
41 | }
|
42 |
|
43 | const compiler = api.createWebpackCompiler(webpackConfig)
|
44 |
|
45 | const devServerOptions = Object.assign(
|
46 | {
|
47 | quiet: true,
|
48 | historyApiFallback: true,
|
49 | overlay: true,
|
50 | disableHostCheck: true,
|
51 | publicPath: webpackConfig.output.publicPath,
|
52 | contentBase:
|
53 | api.config.publicFolder && api.resolveCwd(api.config.publicFolder),
|
54 | watchContentBase: true,
|
55 | stats: {
|
56 | colors: true
|
57 | }
|
58 | },
|
59 | devServer,
|
60 | {
|
61 | proxy:
|
62 | typeof devServer.proxy === 'string'
|
63 | ? require('@poi/dev-utils/prepareProxy')(
|
64 | devServer.proxy,
|
65 | api.resolveCwd(api.config.publicFolder),
|
66 | api.cli.options.debug
|
67 | )
|
68 | : devServer.proxy
|
69 | }
|
70 | )
|
71 |
|
72 | const existingBefore = devServerOptions.before
|
73 | devServerOptions.before = server => {
|
74 | server.use(
|
75 | require('@poi/dev-utils/launchEditorEndpoint'),
|
76 | require('launch-editor-middleware')(() =>
|
77 | console.log(
|
78 | `To specify an editor, sepcify the EDITOR env variable or ` +
|
79 | `add "editor" field to your Vue project config.\n`
|
80 | )
|
81 | )
|
82 | )
|
83 | server.use(require('@poi/dev-utils/skipServiceWorker')())
|
84 | existingBefore && existingBefore(server)
|
85 | }
|
86 |
|
87 | const exitingAfter = devServerOptions.after
|
88 | devServerOptions.after = server => {
|
89 | exitingAfter && exitingAfter(server)
|
90 | api.hooks.invoke('onCreateServer', server)
|
91 | }
|
92 |
|
93 | const WebpackDevServer = require('webpack-dev-server')
|
94 | const server = new WebpackDevServer(compiler, devServerOptions)
|
95 |
|
96 | server.listen(port, host)
|
97 | })
|
98 | })
|
99 |
|
100 | api.hook('createWebpackChain', config => {
|
101 | if (!api.cli.options.serve) return
|
102 |
|
103 | config.devtool('cheap-module-eval-source-map')
|
104 |
|
105 | const { hotEntries, hot } = api.config.devServer
|
106 |
|
107 | if (hot) {
|
108 | for (const entry of hotEntries) {
|
109 | if (config.entryPoints.has(entry)) {
|
110 | config.entry(entry).prepend('#webpack-hot-client')
|
111 | }
|
112 | }
|
113 |
|
114 | const { HotModuleReplacementPlugin } = require('webpack')
|
115 | HotModuleReplacementPlugin.__expression = `require('webpack').HotModuleReplacementPlugin`
|
116 |
|
117 | config.plugin('hot').use(HotModuleReplacementPlugin)
|
118 | }
|
119 |
|
120 |
|
121 | if (config.plugins.has('print-status')) {
|
122 | config.plugin('print-status').tap(([options]) => [
|
123 | Object.assign(options, {
|
124 | printFileStats: false
|
125 | })
|
126 | ])
|
127 | }
|
128 |
|
129 |
|
130 | config.plugins.delete('copy-public-folder')
|
131 | })
|
132 | }
|