27 | You may be seeing this error due to misconfigured options.
28 | Please see this FAQ question for information on possible causes and remedies.
29 |
${staticPaths.join('
')}
`;
32 | const css = ``;
77 | const html = `${css}${body}`;
78 |
79 | ctx.body = html; // eslint-disable-line no-param-reassign
80 | ctx.status = 404; // eslint-disable-line no-param-reassign
81 | };
82 |
83 | const getBuiltins = (app, options) => {
84 | const compress = (opts) => {
85 | // only enable compress middleware if the user has explictly enabled it
86 | if (opts || options.compress) {
87 | app.use(koaCompress(opts || options.compress));
88 | }
89 | };
90 |
91 | const four0four = (fn = () => {}) => {
92 | app.use(async (ctx, next) => {
93 | await next();
94 | if (ctx.status === 404) {
95 | render404(ctx);
96 | fn(ctx);
97 | }
98 | });
99 | };
100 |
101 | const headers = (reqHeaders) => {
102 | const headrs = reqHeaders || (options.headers || {});
103 | app.use(async (ctx, next) => {
104 | await next();
105 | for (const headr of Object.keys(headrs)) {
106 | ctx.set(headr, headrs[headr]);
107 | }
108 | });
109 | };
110 |
111 | const historyFallback = () => {
112 | if (options.historyFallback) {
113 | // https://github.com/shellscape/webpack-plugin-serve/issues/94
114 | // When using Firefox, the browser sends an accept header for /wps when using connect-history-api-fallback
115 | app.use(async (ctx, next) => {
116 | if (ctx.path.match(/^\/wps/)) {
117 | const { accept, ...reqHeaders } = ctx.request.header;
118 | ctx.request.header = reqHeaders; // eslint-disable-line no-param-reassign
119 | }
120 | await next();
121 | });
122 |
123 | app.use(convert(historyApiFallback(options.historyFallback)));
124 | }
125 | };
126 |
127 | const statik = (root, opts = {}) => {
128 | const paths = [].concat(root || options.static);
129 | staticPaths = paths;
130 | for (const path of paths) {
131 | app.use(koaStatic(path, opts));
132 | }
133 | };
134 |
135 | const proxy = (...args) => convert(createProxyMiddleware(...args));
136 | const websocket = () => app.use(wsMiddleware);
137 |
138 | proxy.skip = true;
139 |
140 | // by default, middleware are executed in the order they appear here.
141 | // the order of the properties returned in this object are important.
142 | return {
143 | compress: onetime(compress),
144 | headers: onetime(headers),
145 | historyFallback: onetime(historyFallback),
146 | static: onetime(statik),
147 | websocket: onetime(websocket),
148 | proxy,
149 | four0four: onetime(four0four)
150 | };
151 | };
152 |
153 | module.exports = { getBuiltins };
154 |
--------------------------------------------------------------------------------
/lib/plugins/hmr.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 2018 Andrew Powell
3 |
4 | This Source Code Form is subject to the terms of the Mozilla Public
5 | License, v. 2.0. If a copy of the MPL was not distributed with this
6 | file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 |
8 | The above copyright notice and this permission notice shall be
9 | included in all copies or substantial portions of this Source Code Form.
10 | */
11 | const { HotModuleReplacementPlugin, version } = require('webpack');
12 |
13 | const { getMajorVersion } = require('../helpers');
14 |
15 | const { PluginExistsError } = require('../errors');
16 |
17 | const addPlugin = (compiler) => {
18 | const hmrPlugin = new HotModuleReplacementPlugin();
19 | hmrPlugin.apply(compiler);
20 | };
21 |
22 | const init = function init(compiler, log) {
23 | const webpackMajorVersion = getMajorVersion(version);
24 | // eslint-disable-next-line no-param-reassign
25 | compiler.options.output = Object.assign(compiler.options.output, {
26 | hotUpdateChunkFilename: `${compiler.wpsId}-[id]-wps-hmr.js`,
27 | hotUpdateMainFilename:
28 | webpackMajorVersion >= 5
29 | ? `[runtime]-${compiler.wpsId}-wps-hmr.json`
30 | : `${compiler.wpsId}-wps-hmr.json`
31 | });
32 |
33 | const hasHMRPlugin = compiler.options.plugins.some(
34 | (plugin) => plugin instanceof HotModuleReplacementPlugin
35 | );
36 |
37 | /* istanbul ignore else */
38 | if (!hasHMRPlugin) {
39 | addPlugin(compiler);
40 | } else {
41 | log.error(
42 | 'webpack-plugin-serve adds HotModuleReplacementPlugin automatically. Please remove it from your config.'
43 | );
44 | throw new PluginExistsError(
45 | 'HotModuleReplacementPlugin exists in the specified configuration.'
46 | );
47 | }
48 | };
49 |
50 | module.exports = { init };
51 |
--------------------------------------------------------------------------------
/lib/plugins/ramdisk.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 2018 Andrew Powell
3 |
4 | This Source Code Form is subject to the terms of the Mozilla Public
5 | License, v. 2.0. If a copy of the MPL was not distributed with this
6 | file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 |
8 | The above copyright notice and this permission notice shall be
9 | included in all copies or substantial portions of this Source Code Form.
10 | */
11 | /* eslint-disable no-param-reassign */
12 | const crypto = require('crypto');
13 | const { symlinkSync, readFileSync } = require('fs');
14 | const { basename, join, resolve } = require('path');
15 |
16 | const isCwd = require('is-path-cwd');
17 | const escalade = require('escalade/sync');
18 | const rm = require('rimraf');
19 | const { WebpackPluginRamdisk } = require('webpack-plugin-ramdisk');
20 |
21 | const { PluginExistsError, RamdiskPathError } = require('../errors');
22 |
23 | const readPkgName = () => {
24 | const pkgPath = escalade(process.cwd(), (dir, names) => {
25 | if (names.includes('package.json')) {
26 | return 'package.json';
27 | }
28 | return false;
29 | });
30 | // istanbul ignore if
31 | if (pkgPath == null) {
32 | return null;
33 | }
34 | try {
35 | const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));
36 | return pkg.name;
37 | } catch (error) {
38 | // istanbul ignore next
39 | return null;
40 | }
41 | };
42 |
43 | module.exports = {
44 | init(compiler, options) {
45 | const hasPlugin = compiler.options.plugins.some(
46 | (plugin) => plugin instanceof WebpackPluginRamdisk
47 | );
48 |
49 | /* istanbul ignore if */
50 | if (hasPlugin) {
51 | this.log.error(
52 | 'webpack-plugin-serve adds WebpackRamdiskPlugin automatically. Please remove it from your config.'
53 | );
54 | throw new PluginExistsError('WebpackRamdiskPlugin exists in the specified configuration.');
55 | }
56 |
57 | let pkgName = readPkgName();
58 | const { path } = compiler.options.output;
59 | const lastSegment = basename(path);
60 | const errorInfo = `The ramdisk option creates a symlink from \`output.path\`, to the ramdisk build output path, and must remove any existing \`output.path\` to do so.`;
61 |
62 | // if output.path is /batman/batcave, and the user is running the build with wsp from
63 | // /batman/batcave, then the process will try and delete cwd, which we don't want for a number
64 | // of reasons
65 | // console.log('output.path:', resolve(path));
66 | // console.log('process.cwd:', process.cwd());
67 | if (isCwd(path)) {
68 | throw new RamdiskPathError(
69 | `Cannot remove current working directory. ${errorInfo} Please run from another path, or choose a different \`output.path\`.`
70 | );
71 | }
72 |
73 | // if output.path is /batman/batcave, and the compiler context is not set and cwd is
74 | // /batman/batcave, or the context is the same as output.path, then the process will try and
75 | // delete the context directory, which probably contains src, configs, etc. throw an error
76 | // and be overly cautious rather than let the user do something bad. oddly enough, webpack
77 | // doesn't protect against context === output.path.
78 | if (resolve(compiler.context) === resolve(path)) {
79 | throw new RamdiskPathError(
80 | `Cannot remove ${path}. ${errorInfo} Please set the \`context\` to a another path, choose a different \`output.path\`.`
81 | );
82 | }
83 |
84 | if (!pkgName) {
85 | // use md5 for a short hash that'll be consistent between wps starts
86 | const md5 = crypto.createHash('md5');
87 | md5.update(path);
88 | pkgName = md5.digest('hex');
89 | }
90 |
91 | const newPath = join(pkgName, lastSegment);
92 |
93 | // clean up the output path in prep for the ramdisk plugin
94 | compiler.options.output.path = newPath;
95 |
96 | this.log.info(`Ramdisk enabled`);
97 |
98 | const defaultOptions = { name: 'wps' };
99 | const plugin = new WebpackPluginRamdisk(
100 | typeof options === 'object' ? { ...options, ...defaultOptions } : defaultOptions
101 | );
102 | plugin.apply(compiler);
103 |
104 | rm.sync(path);
105 |
106 | symlinkSync(compiler.options.output.path, path);
107 | }
108 | };
109 |
--------------------------------------------------------------------------------
/lib/routes.js:
--------------------------------------------------------------------------------
1 | /*
2 | Copyright © 2018 Andrew Powell
3 |
4 | This Source Code Form is subject to the terms of the Mozilla Public
5 | License, v. 2.0. If a copy of the MPL was not distributed with this
6 | file, You can obtain one at http://mozilla.org/MPL/2.0/.
7 |
8 | The above copyright notice and this permission notice shall be
9 | included in all copies or substantial portions of this Source Code Form.
10 | */
11 | const router = require('koa-route');
12 | const stringify = require('json-stringify-safe');
13 | const stripAnsi = require('strip-ansi');
14 |
15 | const prep = (data) => stringify(data);
16 |
17 | const statsOptions = {
18 | all: false,
19 | cached: true,
20 | children: true,
21 | hash: true,
22 | modules: true,
23 | timings: true,
24 | exclude: ['node_modules', 'bower_components', 'components']
25 | };
26 |
27 | const setupRoutes = function setupRoutes() {
28 | const { app, options } = this;
29 | const events = ['build', 'done', 'invalid', 'progress'];
30 | const connect = async (ctx) => {
31 | if (ctx.ws) {
32 | const socket = await ctx.ws();
33 | const send = (data) => {
34 | if (socket.readyState !== 1) {
35 | return;
36 | }
37 | socket.send(data);
38 | };
39 |
40 | socket.build = (compilerName = '
12 | Edit src/App.js
and save to reload.
13 |