lucid-package 0.0.88 → 0.0.89

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lucid-package",
3
- "version": "0.0.88",
3
+ "version": "0.0.89",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -13,6 +13,7 @@
13
13
  "@types/argparse": "^2.0.10",
14
14
  "@types/express": "^4.17.13",
15
15
  "@types/node": "^16.11.11",
16
+ "@types/webpack": "^5.28.5",
16
17
  "prettier": "file:../../cake/node_modules/prettier",
17
18
  "prettier-plugin-organize-imports": "file:../../cake/node_modules/prettier-plugin-organize-imports"
18
19
  },
@@ -1,3 +1,4 @@
1
+ import { Compiler } from 'webpack';
1
2
  export declare function createEditorExtension(name: string, isInternalTesting: boolean, skipSDKDependency: boolean): Promise<void>;
2
3
  export declare function buildEditorExtension(name: string, isInternalTesting: boolean, quiet?: boolean): Promise<void>;
3
4
  export declare function updateExtensionSDK(name: string): Promise<void>;
@@ -6,10 +7,13 @@ export declare function updateExtensionSDK(name: string): Promise<void>;
6
7
  * @param name The editor extension name
7
8
  * @param quiet If true, will only show errors in output
8
9
  */
9
- export declare function watchEditorExtension(name: string, isInternalTesting: boolean, quiet?: boolean): Promise<void>;
10
+ export declare function watchEditorExtension(name: string, isInternalTesting: boolean, quiet?: boolean): Promise<{
11
+ name: string;
12
+ compiler: Compiler;
13
+ }>;
10
14
  /**
11
15
  * Runs the editor extensions and shape libraries in debug mode, including watching code for changes.
12
16
  * @param extensionNames The names of the editor extensions
13
17
  * @param quiet If true, will only show errors in output
14
18
  */
15
- export declare function debugEditorExtension(extensionNames: string[], quiet?: boolean, pickAnyPort?: boolean): Promise<void>;
19
+ export declare function debugEditorExtension(extensionNames: string[], isInternalTesting: boolean, quiet?: boolean, pickAnyPort?: boolean): Promise<void>;
@@ -1,7 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.debugEditorExtension = exports.watchEditorExtension = exports.updateExtensionSDK = exports.buildEditorExtension = exports.createEditorExtension = void 0;
4
- const child_process = require("child_process");
5
4
  const express = require("express");
6
5
  const oldFs = require("fs");
7
6
  const fs = require("fs/promises");
@@ -14,6 +13,7 @@ const packagemanifest_1 = require("./packagemanifest");
14
13
  const shapelibrary_1 = require("./shapelibrary");
15
14
  const shellutil_1 = require("./shellutil");
16
15
  const supportedproduct_1 = require("./supportedproduct");
16
+ const webpack = require('webpack');
17
17
  const WebPackCLI = require('webpack-cli');
18
18
  const ws = require('ws');
19
19
  const chokidar = require('chokidar');
@@ -64,11 +64,23 @@ exports.updateExtensionSDK = updateExtensionSDK;
64
64
  * @param quiet If true, will only show errors in output
65
65
  */
66
66
  async function watchEditorExtension(name, isInternalTesting, quiet = false) {
67
+ const originalDirectory = process.cwd();
67
68
  const extensionCodePath = path.join('editorextensions', await getExtensionCodeDirectoryName(name));
68
69
  process.chdir(extensionCodePath);
69
70
  (0, installationutil_1.installDependenciesIfNeeded)(isInternalTesting);
70
- const cli = new WebPackCLI();
71
- cli.run(['node', 'webpack', '--watch', '--env', 'environment=dev', ...(quiet ? ['--stats', 'errors-only'] : [])]);
71
+ const webpackConfigExport = require(path.resolve('webpack.config.js'));
72
+ // For backwards compatibility, we need to support extensions where the webpack config is a fuction or an object
73
+ const webpackConfig = typeof webpackConfigExport == 'function' ? webpackConfigExport({ environment: 'dev' }) : webpackConfigExport;
74
+ webpackConfig.mode = 'development';
75
+ if (quiet) {
76
+ webpackConfig.stats = 'errors-only';
77
+ }
78
+ const compiler = webpack(webpackConfig);
79
+ compiler.watch({}, (err, stats) => {
80
+ console.log(stats?.toString({ colors: true }));
81
+ });
82
+ process.chdir(originalDirectory);
83
+ return { name, compiler };
72
84
  }
73
85
  exports.watchEditorExtension = watchEditorExtension;
74
86
  /**
@@ -76,16 +88,14 @@ exports.watchEditorExtension = watchEditorExtension;
76
88
  * @param extensionNames The names of the editor extensions
77
89
  * @param quiet If true, will only show errors in output
78
90
  */
79
- async function debugEditorExtension(extensionNames, quiet = false, pickAnyPort = false) {
80
- let port = 9900;
81
- await Promise.all(extensionNames.map(async (name) => {
82
- const child = child_process.spawn(`"${process.argv[0]}" "${process.argv[1]}" watch-editor-extension ${name} ${quiet ? '--quiet ' : ''}`, {
83
- stdio: 'inherit',
84
- shell: true,
85
- });
86
- return child;
87
- }));
91
+ async function debugEditorExtension(extensionNames, isInternalTesting, quiet = false, pickAnyPort = false) {
92
+ const port = 9900;
93
+ const watchers = await Promise.all(extensionNames.map(async (name) => watchEditorExtension(name, isInternalTesting, quiet)));
88
94
  const app = express();
95
+ const server = listen(app, port, pickAnyPort);
96
+ setupWebSockets(server);
97
+ const errorLog = new Map();
98
+ recordErrors(watchers, errorLog);
89
99
  app.use(cors_1.corsAllowLucid);
90
100
  app.get(['/extension.js', '/editorextension/:name/extension.js'], async (req, res) => {
91
101
  const name = req.params['name'] ?? extensionNames[0];
@@ -176,6 +186,9 @@ async function debugEditorExtension(extensionNames, quiet = false, pickAnyPort =
176
186
  res.set({ 'Content-Type': 'text/html' });
177
187
  res.send(req.query['source']);
178
188
  });
189
+ app.get('/editorextensions/errors', async (req, res) => {
190
+ res.send(JSON.stringify(Array.from(errorLog.entries())));
191
+ });
179
192
  // Static resources in the "public" directory of the package
180
193
  const manifest = await (0, packagemanifest_1.readManifest)('local');
181
194
  if (manifest['public']) {
@@ -185,48 +198,63 @@ async function debugEditorExtension(extensionNames, quiet = false, pickAnyPort =
185
198
  }
186
199
  }
187
200
  app.use('/resources', express.static('public'));
188
- const listen = () => {
189
- const server = app
190
- .listen(port, 'localhost', () => {
191
- console.log('Listening at http://localhost:' + port + '/extension.js');
192
- // Watch for any editor extension changes, and inform watchers that they need to refresh them.
193
- const wss = new ws.Server({ server, path: '/editorExtensions/changes' });
194
- const sockets = [];
195
- wss.on('connection', (ws) => {
196
- sockets.push(ws);
197
- });
198
- // Changes to a file can trigger changes in other files. We debounce all changes so that
199
- // we don't send multiple "refresh" messages.
200
- let timeout = null;
201
- chokidar.watch([['./']]).on('all', () => {
202
- if (timeout) {
203
- clearTimeout(timeout);
204
- }
205
- timeout = setTimeout(() => {
206
- for (const socket of sockets) {
207
- socket.send('refresh');
208
- }
209
- }, 100);
210
- });
211
- (0, shapelibrary_1.debugShapeLibraries)(undefined, pickAnyPort);
212
- })
213
- .on('error', (err) => {
214
- if (err.code === 'EADDRINUSE') {
215
- if (pickAnyPort && port < 15000) {
216
- port++;
217
- listen();
218
- }
219
- else {
220
- console.error('Failed to listen for extension');
221
- console.error(err);
222
- process.exit(1);
223
- }
201
+ }
202
+ exports.debugEditorExtension = debugEditorExtension;
203
+ function listen(app, port, pickAnyPort) {
204
+ return app
205
+ .listen(port, 'localhost', () => {
206
+ console.log('Listening at http://localhost:' + port + '/extension.js');
207
+ (0, shapelibrary_1.debugShapeLibraries)(undefined, pickAnyPort);
208
+ })
209
+ .on('error', (err) => {
210
+ if (err.code === 'EADDRINUSE') {
211
+ if (pickAnyPort && port < 15000) {
212
+ port++;
213
+ listen(app, port, pickAnyPort);
214
+ }
215
+ else {
216
+ console.error('Failed to listen for extension');
217
+ console.error(err);
218
+ process.exit(1);
219
+ }
220
+ }
221
+ });
222
+ }
223
+ /**
224
+ * Inform the editor that extensions need to be refreshed when watchers detect changes.
225
+ */
226
+ function setupWebSockets(server) {
227
+ // We use chokidar to listen for changes instead of webpacks's on compilation done hook. This is because
228
+ // changes to the manifest or credentials file do not trigger webpack to recompile the extension.
229
+ const sockets = [];
230
+ const wss = new ws.Server({ server, path: '/editorExtensions/changes' });
231
+ wss.on('connection', (ws) => sockets.push(ws));
232
+ // Changes to a file can trigger changes in other files. We debounce all changes so that
233
+ // we don't send multiple "refresh" messages.
234
+ let timeout = null;
235
+ chokidar.watch([['./']]).on('all', () => {
236
+ if (timeout) {
237
+ clearTimeout(timeout);
238
+ }
239
+ timeout = setTimeout(() => {
240
+ for (const socket of sockets) {
241
+ socket.send('refresh');
242
+ }
243
+ }, 100);
244
+ });
245
+ }
246
+ function recordErrors(watchers, errorLog) {
247
+ watchers.forEach((watcher) => {
248
+ watcher.compiler.hooks.done.tap('CompilationDonePlugin', (stats) => {
249
+ if (stats.hasErrors()) {
250
+ errorLog.set(watcher.name, stats.toString({ all: false, colors: false, errors: true }));
251
+ }
252
+ else {
253
+ errorLog.delete(watcher.name);
224
254
  }
225
255
  });
226
- };
227
- listen();
256
+ });
228
257
  }
229
- exports.debugEditorExtension = debugEditorExtension;
230
258
  async function getExtensionManifest(name) {
231
259
  const manifest = await (0, packagemanifest_1.readManifest)('local');
232
260
  return { manifest, extensionManifest: manifest['extensions']?.find((one) => one['name'] === name) };
package/src/index.js CHANGED
@@ -174,7 +174,7 @@ class LucidSuiteExtensionCLI {
174
174
  await (0, shapelibrary_1.debugShapeLibraries)();
175
175
  break;
176
176
  case 'test-editor-extension':
177
- await (0, editorextension_1.debugEditorExtension)(parsed['name'], parsed['quiet'], parsed['anyport']);
177
+ await (0, editorextension_1.debugEditorExtension)(parsed['name'], isInternalTesting, parsed['quiet'], parsed['anyport']);
178
178
  break;
179
179
  case 'watch-editor-extension':
180
180
  await (0, editorextension_1.watchEditorExtension)(parsed['name'], isInternalTesting, parsed['quiet']);