@teambit/preview 1.0.186 → 1.0.188

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.
@@ -1,6 +1,4 @@
1
- import React, { useState, useEffect, Dispatch, SetStateAction } from 'react';
2
1
  import { flatten } from 'lodash';
3
- import { PreviewServerStatus } from '@teambit/preview.cli.preview-server-status';
4
2
  import { BundlerMain, ComponentServer } from '@teambit/bundler';
5
3
  import { PubsubMain } from '@teambit/pubsub';
6
4
  import { ProxyEntry, StartPlugin, StartPluginOptions, UiMain } from '@teambit/ui';
@@ -9,9 +7,17 @@ import { SubscribeToWebpackEvents, CompilationResult } from '@teambit/preview.cl
9
7
  import { CompilationInitiator } from '@teambit/compiler';
10
8
  import { Logger } from '@teambit/logger';
11
9
  import { CheckTypes, WatcherMain } from '@teambit/watcher';
10
+ import chalk from 'chalk';
12
11
 
13
- type CompilationServers = Record<string, CompilationResult>;
14
- type ServersSetter = Dispatch<SetStateAction<CompilationServers>>;
12
+ type ServerState = {
13
+ isCompiling?: boolean;
14
+ isReady?: boolean;
15
+ errors?: Error[];
16
+ warnings?: Error[];
17
+ results?: any[];
18
+ };
19
+
20
+ type ServerStateMap = Record<string, ServerState>;
15
21
 
16
22
  export class PreviewStartPlugin implements StartPlugin {
17
23
  constructor(
@@ -24,6 +30,8 @@ export class PreviewStartPlugin implements StartPlugin {
24
30
  ) {}
25
31
 
26
32
  previewServers: ComponentServer[] = [];
33
+ serversState: ServerStateMap = {};
34
+ serversMap: Record<string, ComponentServer> = {};
27
35
 
28
36
  async initiate(options: StartPluginOptions) {
29
37
  this.listenToDevServers();
@@ -31,9 +39,12 @@ export class PreviewStartPlugin implements StartPlugin {
31
39
  const components = await this.workspace.getComponentsByUserInput(!options.pattern, options.pattern);
32
40
  // TODO: logic for creating preview servers must be refactored to this aspect from the DevServer aspect.
33
41
  const previewServers = await this.bundler.devServer(components);
34
- // eslint-disable-next-line @typescript-eslint/no-misused-promises
35
- previewServers.forEach((server) => server.listen());
36
- // DON'T add wait! this promise never resolves, so it would stop the start process!
42
+ previewServers.forEach((server) => {
43
+ this.serversMap[server.context.envRuntime.id] = server;
44
+ // DON'T add wait! this promise never resolves, so it would stop the start process!
45
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
46
+ server.listen();
47
+ });
37
48
  this.watcher
38
49
  .watch({
39
50
  spawnTSServer: true,
@@ -73,43 +84,110 @@ export class PreviewStartPlugin implements StartPlugin {
73
84
  // keep state changes immutable!
74
85
  SubscribeToWebpackEvents(this.pubsub, {
75
86
  onStart: (id) => {
76
- this.updateServers((state) => ({
77
- ...state,
78
- [id]: { compiling: true },
79
- }));
87
+ this.handleOnStartCompiling(id);
80
88
  },
81
89
  onDone: (id, results) => {
82
- this.updateServers((state) => ({
83
- ...state,
84
- [id]: results,
85
- }));
90
+ this.handleOnDoneCompiling(id, results);
86
91
  },
87
92
  });
88
93
  }
89
94
 
95
+ private handleOnStartCompiling(id: string) {
96
+ this.serversState[id] = { isCompiling: true };
97
+ const spinnerId = getSpinnerId(id);
98
+ const text = getSpinnerCompilingMessage(this.serversMap[id]);
99
+ this.logger.multiSpinner.add(spinnerId, { text });
100
+ }
101
+
102
+ private handleOnDoneCompiling(id: string, results: CompilationResult) {
103
+ this.serversState[id] = {
104
+ isCompiling: false,
105
+ isReady: true,
106
+ errors: results.errors,
107
+ warnings: results.warnings,
108
+ };
109
+ const previewServer = this.serversMap[id];
110
+ const spinnerId = getSpinnerId(id);
111
+ const errors = results.errors || [];
112
+ const hasErrors = !!errors.length;
113
+ const warnings = getWarningsWithoutIgnored(results.warnings);
114
+ const hasWarnings = !!warnings.length;
115
+ const url = `http://localhost:${previewServer.port}`;
116
+ const text = getSpinnerDoneMessage(this.serversMap[id], errors, warnings, url);
117
+ if (hasErrors) {
118
+ this.logger.multiSpinner.fail(spinnerId, { text });
119
+ } else if (hasWarnings) {
120
+ this.logger.multiSpinner.warn(spinnerId, { text });
121
+ } else {
122
+ this.logger.multiSpinner.succeed(spinnerId, { text });
123
+ }
124
+
125
+ const noneAreCompiling = Object.values(this.serversState).every((x) => !x.isCompiling);
126
+ if (noneAreCompiling) this.setReady();
127
+ }
128
+
90
129
  private setReady: () => void;
91
130
  private readyPromise = new Promise<void>((resolve) => (this.setReady = resolve));
92
131
  get whenReady(): Promise<void> {
93
132
  return this.readyPromise;
94
133
  }
134
+ }
135
+
136
+ function getWarningsWithoutIgnored(warnings?: Error[]): Error[] {
137
+ if (!warnings || !warnings.length) return [];
138
+ const IGNORE_WARNINGS = [
139
+ // Webpack 5+ has no facility to disable this warning.
140
+ // System.import is used in @angular/core for deprecated string-form lazy routes
141
+ /System.import\(\) is deprecated and will be removed soon/i,
142
+ // We need to include all the files in the compilation because we don't know what people will use in their compositions
143
+ /is part of the TypeScript compilation but it's unused/i,
144
+ // https://github.com/webpack-contrib/source-map-loader/blob/b2de4249c7431dd8432da607e08f0f65e9d64219/src/index.js#L83
145
+ /Failed to parse source map from/,
146
+ ];
147
+ warnings.filter((warning) => !IGNORE_WARNINGS.find((reg) => warning?.message?.match(reg)));
148
+ return warnings;
149
+ }
150
+
151
+ function getSpinnerId(envId: string) {
152
+ return `preview-${envId}`;
153
+ }
154
+
155
+ function getSpinnerCompilingMessage(server: ComponentServer, verbose = false) {
156
+ const prefix = 'COMPILING';
157
+ const envId = chalk.cyan(server.context.envRuntime.id);
158
+ let includedEnvs = '';
159
+ if (server.context.relatedContexts && server.context.relatedContexts.length > 1) {
160
+ includedEnvs = `on behalf of ${chalk.cyan(stringifyIncludedEnvs(server.context.relatedContexts, verbose))}`;
161
+ }
162
+ return `${prefix} ${envId} ${includedEnvs}`;
163
+ }
164
+
165
+ function getSpinnerDoneMessage(
166
+ server: ComponentServer,
167
+ errors: Error[],
168
+ warnings: Error[],
169
+ url: string,
170
+ verbose = false
171
+ ) {
172
+ const hasErrors = !!errors.length;
173
+ const hasWarnings = !!warnings.length;
174
+ const prefix = hasErrors ? 'FAILED' : 'RUNNING';
175
+ const envId = chalk.cyan(server.context.envRuntime.id);
176
+ let includedEnvs = '';
177
+ if (server.context.relatedContexts && server.context.relatedContexts.length > 1) {
178
+ includedEnvs = ` on behalf of ${chalk.cyan(stringifyIncludedEnvs(server.context.relatedContexts, verbose))}`;
179
+ }
180
+ const errorsTxt = hasErrors ? errors.map((err) => err.message).join('\n') : '';
181
+ const errorsTxtWithTitle = hasErrors ? chalk.red(`\nErrors:\n${errorsTxt}`) : '';
182
+ const warningsTxt = hasWarnings ? warnings.map((warning) => warning.message).join('\n') : '';
183
+ const warningsTxtWithTitle = hasWarnings ? chalk.yellow(`\nWarnings:\n${warningsTxt}`) : '';
184
+
185
+ const urlMessage = hasErrors ? '' : `at ${chalk.cyan(url)}`;
186
+ return `${prefix} ${envId}${includedEnvs} ${urlMessage} ${errorsTxtWithTitle} ${warningsTxtWithTitle}`;
187
+ }
95
188
 
96
- private initialState: CompilationServers = {};
97
- // implements react-like setter (value or updater)
98
- private updateServers: ServersSetter = (servers) => {
99
- this.initialState = typeof servers === 'function' ? servers(this.initialState) : servers;
100
- return servers;
101
- };
102
-
103
- render = () => {
104
- const [servers, setServers] = useState<CompilationServers>(this.initialState);
105
- this.updateServers = setServers;
106
- this.initialState = {};
107
-
108
- useEffect(() => {
109
- const noneAreCompiling = Object.values(servers).every((x) => !x.compiling);
110
- if (noneAreCompiling) this.setReady();
111
- }, [servers]);
112
-
113
- return <PreviewServerStatus previewServers={this.previewServers} serverStats={servers} />;
114
- };
189
+ function stringifyIncludedEnvs(includedEnvs: string[] = [], verbose = false) {
190
+ if (includedEnvs.length < 2) return '';
191
+ if (includedEnvs.length > 2 && !verbose) return ` ${includedEnvs.length} other envs`;
192
+ return includedEnvs.join(', ');
115
193
  }