@teambit/preview 0.0.625 → 0.0.631

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.
Files changed (68) hide show
  1. package/__preview-1643039669895.js +1 -0
  2. package/dist/artifact-file-middleware.d.ts +12 -0
  3. package/dist/artifact-file-middleware.js +81 -0
  4. package/dist/artifact-file-middleware.js.map +1 -0
  5. package/dist/bundling-strategy.d.ts +6 -1
  6. package/dist/component-preview.route.d.ts +20 -0
  7. package/dist/component-preview.route.js +83 -0
  8. package/dist/component-preview.route.js.map +1 -0
  9. package/dist/env-preview-template.task.d.ts +42 -0
  10. package/dist/env-preview-template.task.js +309 -0
  11. package/dist/env-preview-template.task.js.map +1 -0
  12. package/dist/env-template.route.d.ts +26 -0
  13. package/dist/env-template.route.js +89 -0
  14. package/dist/env-template.route.js.map +1 -0
  15. package/dist/generate-link.d.ts +1 -1
  16. package/dist/generate-link.js +3 -3
  17. package/dist/generate-link.js.map +1 -1
  18. package/dist/index.d.ts +1 -1
  19. package/dist/index.js.map +1 -1
  20. package/dist/preview-artifact.d.ts +2 -0
  21. package/dist/preview-artifact.js +21 -0
  22. package/dist/preview-artifact.js.map +1 -1
  23. package/dist/preview-assets.route.d.ts +19 -0
  24. package/dist/preview-assets.route.js +66 -0
  25. package/dist/preview-assets.route.js.map +1 -0
  26. package/dist/preview-definition.d.ts +16 -3
  27. package/dist/preview.graphql.d.ts +8 -1
  28. package/dist/preview.graphql.js +13 -2
  29. package/dist/preview.graphql.js.map +1 -1
  30. package/dist/preview.main.runtime.d.ts +78 -11
  31. package/dist/preview.main.runtime.js +251 -18
  32. package/dist/preview.main.runtime.js.map +1 -1
  33. package/dist/preview.preview.runtime.d.ts +11 -2
  34. package/dist/preview.preview.runtime.js +124 -6
  35. package/dist/preview.preview.runtime.js.map +1 -1
  36. package/dist/preview.route.d.ts +3 -7
  37. package/dist/preview.route.js +22 -21
  38. package/dist/preview.route.js.map +1 -1
  39. package/dist/preview.task.d.ts +2 -2
  40. package/dist/preview.task.js +25 -24
  41. package/dist/preview.task.js.map +1 -1
  42. package/dist/strategies/component-strategy.d.ts +52 -12
  43. package/dist/strategies/component-strategy.js +348 -20
  44. package/dist/strategies/component-strategy.js.map +1 -1
  45. package/dist/strategies/env-strategy.d.ts +7 -5
  46. package/dist/strategies/env-strategy.js +27 -1
  47. package/dist/strategies/env-strategy.js.map +1 -1
  48. package/dist/strategies/generate-component-link.d.ts +5 -0
  49. package/dist/strategies/generate-component-link.js +25 -0
  50. package/dist/strategies/generate-component-link.js.map +1 -0
  51. package/dist/types/preview-module.d.ts +1 -0
  52. package/dist/webpack/html.d.ts +2 -0
  53. package/dist/webpack/html.js +31 -0
  54. package/dist/webpack/html.js.map +1 -0
  55. package/dist/webpack/index.d.ts +1 -0
  56. package/dist/webpack/index.js +23 -0
  57. package/dist/webpack/index.js.map +1 -0
  58. package/package-tar/teambit-preview-0.0.631.tgz +0 -0
  59. package/package.json +29 -26
  60. package/preview.main.runtime.tsx +235 -23
  61. package/preview.preview.runtime.tsx +123 -7
  62. package/strategies/component-strategy.ts +329 -23
  63. package/strategies/env-strategy.ts +28 -10
  64. package/strategies/generate-component-link.ts +19 -0
  65. package/types/preview-module.ts +2 -0
  66. package/webpack/html.ts +22 -0
  67. package/webpack/index.ts +1 -0
  68. package/package-tar/teambit-preview-0.0.625.tgz +0 -0
@@ -1,6 +1,7 @@
1
1
  import PubsubAspect, { PubsubPreview } from '@teambit/pubsub';
2
2
  import { Slot, SlotRegistry } from '@teambit/harmony';
3
3
  import { ComponentID } from '@teambit/component-id';
4
+ import crossFetch from 'cross-fetch';
4
5
 
5
6
  import { PreviewNotFound } from './exceptions';
6
7
  import { PreviewType } from './preview-type';
@@ -44,7 +45,7 @@ export class PreviewPreview {
44
45
  /**
45
46
  * render the preview.
46
47
  */
47
- render = () => {
48
+ render = async () => {
48
49
  const { previewName, componentId } = this.getLocation();
49
50
  const name = previewName || this.getDefault();
50
51
 
@@ -52,18 +53,126 @@ export class PreviewPreview {
52
53
  if (!preview || !componentId) {
53
54
  throw new PreviewNotFound(previewName);
54
55
  }
55
- const includes = (preview.include || [])
56
- .map((prevName) => {
56
+ const includesAll = await Promise.all(
57
+ (preview.include || []).map(async (prevName) => {
57
58
  const includedPreview = this.getPreview(prevName);
58
59
  if (!includedPreview) return undefined;
59
60
 
60
- return includedPreview.selectPreviewModel?.(componentId.fullName, PREVIEW_MODULES[prevName]);
61
+ return includedPreview.selectPreviewModel?.(
62
+ componentId.fullName,
63
+ await this.getPreviewModule(prevName, componentId)
64
+ );
61
65
  })
62
- .filter((module) => !!module);
66
+ );
63
67
 
64
- return preview.render(componentId.fullName, PREVIEW_MODULES[name], includes, this.getRenderingContext());
68
+ const includes = includesAll.filter((module) => !!module);
69
+
70
+ return preview.render(
71
+ componentId.fullName,
72
+ await this.getPreviewModule(name, componentId),
73
+ includes,
74
+ this.getRenderingContext()
75
+ );
65
76
  };
66
77
 
78
+ async getPreviewModule(name: string, id: ComponentID): Promise<PreviewModule> {
79
+ if (PREVIEW_MODULES[name].componentMap[id.fullName]) return PREVIEW_MODULES[name];
80
+ // if (!window[name]) throw new PreviewNotFound(name);
81
+ // const isSplitComponentBundle = PREVIEW_MODULES[name].isSplitComponentBundle ?? false;
82
+ // const component = window[id.toStringWithoutVersion()];
83
+ const component: any = await this.fetchComponentPreview(id, name);
84
+
85
+ return {
86
+ mainModule: PREVIEW_MODULES[name].mainModule,
87
+ componentMap: {
88
+ [id.fullName]: component,
89
+ },
90
+ };
91
+ }
92
+
93
+ async fetchComponentPreview(id: ComponentID, name: string) {
94
+ let previewFile;
95
+ const allFiles = await this.fetchComponentPreviewFiles(id, name);
96
+ allFiles.forEach((file) => {
97
+ // We want to run the preview file always last
98
+ if (file.endsWith('-preview.js')) {
99
+ previewFile = file;
100
+ } else {
101
+ this.addComponentFileElement(id, file);
102
+ }
103
+ });
104
+ return new Promise((resolve, reject) => {
105
+ const previewScriptElement = this.getPreviewScriptElement(id, name, previewFile, resolve, reject);
106
+ document.head.appendChild(previewScriptElement);
107
+ });
108
+ }
109
+
110
+ private addComponentFileElement(id: ComponentID, previewBundleFileName: string) {
111
+ if (previewBundleFileName.endsWith('.js')) {
112
+ return this.addComponentFileScriptElement(id, previewBundleFileName);
113
+ }
114
+ return this.addComponentFileLinkElement(id, previewBundleFileName);
115
+ }
116
+
117
+ private async fetchComponentPreviewFiles(id: ComponentID, previewName: string): Promise<string[]> {
118
+ const previewAssetsRoute = `~aspect/preview-assets`;
119
+ const stringId = id.toString();
120
+ const url = `/api/${stringId}/${previewAssetsRoute}`;
121
+
122
+ const res = await crossFetch(url);
123
+ if (res.status >= 400) {
124
+ throw new PreviewNotFound(previewName);
125
+ }
126
+ const parsed = await res.json();
127
+ if (!parsed.files || !parsed.files.length) {
128
+ throw new PreviewNotFound(previewName);
129
+ }
130
+ return parsed.files;
131
+ }
132
+
133
+ private addComponentFileScriptElement(id: ComponentID, previewBundleFileName: string) {
134
+ const script = document.createElement('script');
135
+ script.setAttribute('defer', 'defer');
136
+ const stringId = id.toString();
137
+ const previewRoute = `~aspect/component-preview`;
138
+ const src = `/api/${stringId}/${previewRoute}/${previewBundleFileName}`;
139
+ script.src = src;
140
+ document.head.appendChild(script);
141
+ return script;
142
+ }
143
+
144
+ private addComponentFileLinkElement(id: ComponentID, previewBundleFileName: string) {
145
+ const link = document.createElement('link');
146
+ const stringId = id.toString();
147
+ const previewRoute = `~aspect/component-preview`;
148
+ const href = `/api/${stringId}/${previewRoute}/${previewBundleFileName}`;
149
+ link.setAttribute('href', href);
150
+ if (previewBundleFileName.endsWith('.css')) {
151
+ link.setAttribute('rel', 'stylesheet');
152
+ }
153
+ document.head.appendChild(link);
154
+ return link;
155
+ }
156
+
157
+ private getPreviewScriptElement(id: ComponentID, name: string, previewBundleFileName: string, resolve, reject) {
158
+ const script = document.createElement('script');
159
+ script.setAttribute('defer', 'defer');
160
+ const stringId = id.toString();
161
+ // const previewRoute = `~aspect/preview`;
162
+ const previewRoute = `~aspect/component-preview`;
163
+ const src = `/api/${stringId}/${previewRoute}/${previewBundleFileName}`;
164
+ script.src = src; // generate path to remote scope. [scope url]/
165
+ script.onload = () => {
166
+ const componentPreview = window[`${id.toStringWithoutVersion()}-preview`];
167
+ if (!componentPreview) return reject(new PreviewNotFound(name));
168
+ const targetPreview = componentPreview[name];
169
+ if (!targetPreview) return reject(new PreviewNotFound(name));
170
+
171
+ return resolve(targetPreview);
172
+ };
173
+ return script;
174
+ }
175
+
67
176
  /**
68
177
  * register a new preview.
69
178
  */
@@ -131,6 +240,7 @@ export class PreviewPreview {
131
240
  const preview = new PreviewPreview(pubsub, previewSlot, renderingContextSlot);
132
241
 
133
242
  window.addEventListener('hashchange', () => {
243
+ // eslint-disable-next-line @typescript-eslint/no-floating-promises
134
244
  preview.render();
135
245
  });
136
246
 
@@ -138,9 +248,15 @@ export class PreviewPreview {
138
248
  }
139
249
  }
140
250
 
141
- export function linkModules(previewName: string, defaultModule: any, componentMap: { [key: string]: any }) {
251
+ export function linkModules(
252
+ previewName: string,
253
+ defaultModule: any,
254
+ isSplitComponentBundle: boolean,
255
+ componentMap: { [key: string]: any }
256
+ ) {
142
257
  PREVIEW_MODULES[previewName] = {
143
258
  mainModule: defaultModule,
259
+ isSplitComponentBundle,
144
260
  componentMap,
145
261
  };
146
262
  }
@@ -1,34 +1,340 @@
1
- import { BuildContext } from '@teambit/builder';
2
- import { Target, BundlerResult, BundlerContext } from '@teambit/bundler';
3
- import { BundlingStrategy } from '../bundling-strategy';
4
- import { PreviewDefinition } from '../preview-definition';
5
- import { PreviewTask } from '../preview.task';
1
+ import { readFileSync } from 'fs';
2
+ import { join, resolve, basename } from 'path';
3
+ import { existsSync, mkdirpSync } from 'fs-extra';
4
+ import { Component } from '@teambit/component';
5
+ import { ComponentID } from '@teambit/component-id';
6
+ import { flatten } from 'lodash';
7
+ import { Compiler } from '@teambit/compiler';
8
+ import type { AbstractVinyl } from '@teambit/legacy/dist/consumer/component/sources';
9
+ import type { Capsule } from '@teambit/isolator';
10
+ import { CAPSULE_ARTIFACTS_DIR, ComponentResult } from '@teambit/builder';
11
+ import type { PkgMain } from '@teambit/pkg';
12
+ import { BitError } from '@teambit/bit-error';
13
+ import type { DependencyResolverMain } from '@teambit/dependency-resolver';
14
+ import type { BundlerResult, BundlerContext, Asset, BundlerEntryMap, EntriesAssetsMap } from '@teambit/bundler';
15
+ import { BundlingStrategy, ComputeTargetsContext } from '../bundling-strategy';
16
+ import type { PreviewDefinition } from '../preview-definition';
17
+ import type { ComponentPreviewMetaData, PreviewMain } from '../preview.main.runtime';
18
+ import { generateComponentLink } from './generate-component-link';
6
19
 
20
+ export const PREVIEW_CHUNK_SUFFIX = 'preview';
21
+ export const COMPONENT_CHUNK_SUFFIX = 'component';
22
+ export const PREVIEW_CHUNK_FILENAME_SUFFIX = `${PREVIEW_CHUNK_SUFFIX}.js`;
23
+ export const COMPONENT_CHUNK_FILENAME_SUFFIX = `${COMPONENT_CHUNK_SUFFIX}.js`;
24
+
25
+ export const COMPONENT_STRATEGY_SIZE_KEY_NAME = 'size';
26
+ export const COMPONENT_STRATEGY_ARTIFACT_NAME = 'preview-component';
27
+ /**
28
+ * bundles all components in a given env into the same bundle.
29
+ */
7
30
  export class ComponentBundlingStrategy implements BundlingStrategy {
8
31
  name = 'component';
9
32
 
10
- computeTargets(context: BuildContext, previewDefs: PreviewDefinition[], previewTask: PreviewTask): Promise<Target[]> {
11
- return Promise.all(
12
- context.capsuleNetwork.graphCapsules.map(async (capsule) => {
13
- return {
14
- entries: await previewTask.computePaths(capsule, previewDefs, context),
15
- components: [capsule.component],
16
- outputPath: capsule.path,
17
- };
18
- })
33
+ constructor(private preview: PreviewMain, private pkg: PkgMain, private dependencyResolver: DependencyResolverMain) {}
34
+
35
+ async computeTargets(context: ComputeTargetsContext, previewDefs: PreviewDefinition[]) {
36
+ const outputPath = this.getOutputPath(context);
37
+ if (!existsSync(outputPath)) mkdirpSync(outputPath);
38
+
39
+ // const entriesArr = flatten(
40
+ // await Promise.all(
41
+ // context.capsuleNetwork.seedersCapsules.map((capsule) => {
42
+ // return this.computeComponentEntry(previewDefs, capsule.component, context);
43
+ // }, {})
44
+ // )
45
+ // );
46
+
47
+ const entriesArr = await Promise.all(
48
+ context.capsuleNetwork.seedersCapsules.map((capsule) => {
49
+ return this.computeComponentEntry(previewDefs, capsule.component, context);
50
+ }, {})
19
51
  );
52
+
53
+ const entries: BundlerEntryMap = entriesArr.reduce((entriesMap, entry) => {
54
+ // entriesMap[entry.library.name] = entry;
55
+ Object.assign(entriesMap, entry);
56
+ return entriesMap;
57
+ }, {});
58
+ // const entries = entriesArr.reduce((entriesMap, entry) => {
59
+ // entriesMap[entry.library.name] = entry;
60
+ // return entriesMap;
61
+ // }, {});
62
+
63
+ // const modules = await Promise.all(entriesArr.map(async (entry) => {
64
+ // const dependencies = await this.dependencyResolver.getDependencies(entry.component);
65
+ // const manifest = dependencies.toDependenciesManifest();
66
+ // const peer = Object.entries(manifest.peerDependencies || {}).reduce((acc, [packageName, version]) => {
67
+ // acc[packageName] = {
68
+ // singleton: true,
69
+ // requiredVersion: version
70
+ // };
71
+
72
+ // return acc;
73
+ // }, {});
74
+ // // console.log(entry);
75
+ // return {
76
+ // name: entry.library.name,
77
+ // exposes: {
78
+ // '.': entry.import || ''
79
+ // },
80
+ // shared: {
81
+ // ...manifest.dependencies,
82
+ // ...peer
83
+ // },
84
+ // };
85
+ // }));
86
+
87
+ return [
88
+ {
89
+ // entries: await this.computePaths(outputPath, previewDefs, context),
90
+ entries,
91
+ components: context.components,
92
+ outputPath,
93
+ // modules,
94
+ },
95
+ ];
96
+ }
97
+
98
+ async computeComponentEntry(previewDefs: PreviewDefinition[], component: Component, context: ComputeTargetsContext) {
99
+ const path = await this.computePaths(previewDefs, context, component);
100
+ const [componentPath] = this.getPaths(context, component, [component.mainFile]);
101
+ const componentPreviewChunkId = this.getComponentChunkId(component.id, 'preview');
102
+
103
+ const entries = {
104
+ [componentPreviewChunkId]: {
105
+ filename: this.getComponentChunkFileName(
106
+ component.id.toString({
107
+ fsCompatible: true,
108
+ ignoreVersion: true,
109
+ }),
110
+ 'preview'
111
+ ),
112
+ import: path,
113
+ // dependOn: component.id.toStringWithoutVersion(),
114
+ library: {
115
+ name: componentPreviewChunkId,
116
+ type: 'umd',
117
+ },
118
+ },
119
+ };
120
+ if (context.splitComponentBundle) {
121
+ const componentChunkId = component.id.toStringWithoutVersion();
122
+ entries[componentChunkId] = {
123
+ filename: this.getComponentChunkFileName(
124
+ component.id.toString({
125
+ fsCompatible: true,
126
+ ignoreVersion: true,
127
+ }),
128
+ 'component'
129
+ ),
130
+ import: componentPath,
131
+ library: {
132
+ name: componentChunkId,
133
+ type: 'umd',
134
+ },
135
+ };
136
+ }
137
+ return entries;
138
+ }
139
+
140
+ private getComponentChunkId(componentId: ComponentID, type: 'component' | 'preview') {
141
+ const id =
142
+ type === 'component'
143
+ ? componentId.toStringWithoutVersion()
144
+ : `${componentId.toStringWithoutVersion()}-${PREVIEW_CHUNK_SUFFIX}`;
145
+ return id;
146
+ }
147
+
148
+ private getComponentChunkFileName(idstr: string, type: 'component' | 'preview') {
149
+ const suffix = type === 'component' ? COMPONENT_CHUNK_FILENAME_SUFFIX : PREVIEW_CHUNK_FILENAME_SUFFIX;
150
+ return `${idstr}-${suffix}`;
151
+ }
152
+
153
+ private getAssetAbsolutePath(context: BundlerContext, asset: Asset): string {
154
+ const path = this.getOutputPath(context);
155
+ return join(path, 'public', asset.name);
156
+ }
157
+
158
+ copyAssetsToCapsules(context: BundlerContext, result: BundlerResult) {
159
+ context.components.forEach((component) => {
160
+ const capsule = context.capsuleNetwork.graphCapsules.getCapsule(component.id);
161
+ if (!capsule) return;
162
+ const files = this.findAssetsForComponent(component, result.assets, result.entriesAssetsMap || {});
163
+ if (!files) return;
164
+
165
+ files.forEach((asset) => {
166
+ const filePath = this.getAssetAbsolutePath(context, asset);
167
+ const contents = readFileSync(filePath);
168
+ // const exists = capsule.fs.existsSync(this.getArtifactDirectory());
169
+ // if (!exists) capsule.fs.mkdirSync(this.getArtifactDirectory());
170
+ // We don't use the mkdirSync as it uses the capsule fs which uses memfs, which doesn't know to handle nested none existing folders
171
+ mkdirpSync(join(capsule.path, this.getArtifactDirectory()));
172
+ const filename = basename(asset.name);
173
+ // let filename = asset.name;
174
+ // if (filePath.endsWith('.css')){
175
+ // filename = this.getCssFileName(capsule.component.id);
176
+ // }
177
+ capsule.fs.writeFileSync(join(this.getArtifactDirectory(), filename), contents);
178
+ });
179
+ });
180
+ }
181
+
182
+ // private getCssFileName(componentId: ComponentID): string {
183
+ // return `${componentId.toString({ ignoreVersion: true, fsCompatible: true })}.css`;
184
+ // }
185
+
186
+ private findAssetsForComponent(
187
+ component: Component,
188
+ assets: Asset[],
189
+ entriesAssetsMap: EntriesAssetsMap
190
+ ): Asset[] | undefined {
191
+ if (!assets) return undefined;
192
+
193
+ const componentEntryId = component.id.toStringWithoutVersion();
194
+ const componentPreviewEntryId = this.getComponentChunkId(component.id, 'preview');
195
+ const componentFiles = entriesAssetsMap[componentEntryId]?.assets || [];
196
+ const componentAuxiliaryFiles = entriesAssetsMap[componentEntryId]?.auxiliaryAssets || [];
197
+ const componentPreviewFiles = entriesAssetsMap[componentPreviewEntryId]?.assets || [];
198
+ const componentPreviewAuxiliaryFiles = entriesAssetsMap[componentPreviewEntryId]?.auxiliaryAssets || [];
199
+
200
+ const files = componentFiles
201
+ .concat(componentAuxiliaryFiles)
202
+ .concat(componentPreviewFiles)
203
+ .concat(componentPreviewAuxiliaryFiles);
204
+ return files;
20
205
  }
21
206
 
22
- async computeResults(context: BundlerContext, results: BundlerResult[], previewTask: PreviewTask) {
207
+ private getArtifactDirectory() {
208
+ return join(CAPSULE_ARTIFACTS_DIR, 'preview');
209
+ }
210
+
211
+ private computeComponentMetadata(
212
+ context: BundlerContext,
213
+ result: BundlerResult,
214
+ component: Component
215
+ ): ComponentPreviewMetaData {
216
+ const componentEntryId = component.id.toStringWithoutVersion();
217
+ if (!result?.entriesAssetsMap || !result?.entriesAssetsMap[componentEntryId]) {
218
+ return {};
219
+ }
220
+ const files = (result.entriesAssetsMap[componentEntryId]?.assets || []).map((file) => {
221
+ return {
222
+ name: basename(file.name),
223
+ size: file.size,
224
+ };
225
+ });
226
+ const filesTotalSize = result.entriesAssetsMap[componentEntryId]?.assetsSize || 0;
227
+ const assets = (result.entriesAssetsMap[componentEntryId]?.auxiliaryAssets || []).map((file) => {
228
+ return {
229
+ name: basename(file.name),
230
+ size: file.size,
231
+ };
232
+ });
233
+ const assetsTotalSize = result.entriesAssetsMap[componentEntryId]?.auxiliaryAssetsSize || 0;
234
+ const totalSize = filesTotalSize + assetsTotalSize;
235
+
236
+ const metadata = {
237
+ [COMPONENT_STRATEGY_SIZE_KEY_NAME]: {
238
+ files,
239
+ assets,
240
+ totalFiles: filesTotalSize,
241
+ totalAssets: assetsTotalSize,
242
+ total: totalSize,
243
+ },
244
+ };
245
+ return metadata;
246
+ }
247
+
248
+ async computeResults(context: BundlerContext, results: BundlerResult[]) {
249
+ const result = results[0];
250
+
251
+ this.copyAssetsToCapsules(context, result);
252
+
253
+ const componentsResults: ComponentResult[] = result.components.map((component) => {
254
+ const metadata = this.computeComponentMetadata(context, result, component);
255
+ return {
256
+ component,
257
+ metadata,
258
+ errors: result.errors.map((err) => (typeof err === 'string' ? err : err.message)),
259
+ warning: result.warnings,
260
+ startTime: result.startTime,
261
+ endTime: result.endTime,
262
+ };
263
+ });
264
+
265
+ const artifacts = this.getArtifactDef();
266
+
23
267
  return {
24
- componentsResults: results.map((result) => {
25
- return {
26
- errors: result.errors,
27
- component: result.components[0],
28
- warning: result.warnings,
29
- };
30
- }),
31
- artifacts: [{ name: 'preview', globPatterns: [previewTask.getPreviewDirectory(context)] }],
268
+ componentsResults,
269
+ artifacts,
32
270
  };
33
271
  }
272
+
273
+ private getArtifactDef() {
274
+ // eslint-disable-next-line @typescript-eslint/prefer-as-const
275
+ // const env: 'env' = 'env';
276
+ // const rootDir = this.getDirName(context);
277
+
278
+ return [
279
+ {
280
+ name: COMPONENT_STRATEGY_ARTIFACT_NAME,
281
+ globPatterns: ['**'],
282
+ rootDir: this.getArtifactDirectory(),
283
+ // context: env,
284
+ },
285
+ ];
286
+ }
287
+
288
+ getDirName(context: ComputeTargetsContext) {
289
+ const envName = context.id.replace('/', '__');
290
+ return `${envName}-preview`;
291
+ }
292
+
293
+ private getOutputPath(context: ComputeTargetsContext) {
294
+ return resolve(`${context.capsuleNetwork.capsulesRootDir}/${this.getDirName(context)}`);
295
+ }
296
+
297
+ private getPaths(context: ComputeTargetsContext, component: Component, files: AbstractVinyl[]) {
298
+ const capsule = context.capsuleNetwork.graphCapsules.getCapsule(component.id);
299
+ if (!capsule) return [];
300
+ const compiler: Compiler = context.env.getCompiler();
301
+ return files.map((file) => join(capsule.path, compiler.getDistPathBySrcPath(file.relative)));
302
+ }
303
+
304
+ private getComponentOutputPath(capsule: Capsule) {
305
+ return resolve(`${capsule.path}`);
306
+ }
307
+
308
+ private async computePaths(
309
+ defs: PreviewDefinition[],
310
+ context: ComputeTargetsContext,
311
+ component: Component
312
+ ): Promise<string> {
313
+ // const previewMain = await this.preview.writePreviewRuntime(context);
314
+ const capsule = context.capsuleNetwork.graphCapsules.getCapsule(component.id);
315
+ // if (!capsule) return undefined;
316
+ if (!capsule)
317
+ throw new BitError(
318
+ `could not find capsule for component ${component.id.toString()} during compute paths to bundle`
319
+ );
320
+ const moduleMapsPromise = defs.map(async (previewDef) => {
321
+ const moduleMap = await previewDef.getModuleMap([component]);
322
+ const maybeFiles = moduleMap.get(component);
323
+ if (!maybeFiles || !capsule) return [];
324
+ const [, files] = maybeFiles;
325
+ const compiledPaths = this.getPaths(context, component, files);
326
+ // const files = flatten(paths.toArray().map(([, file]) => file));
327
+
328
+ return {
329
+ prefix: previewDef.prefix,
330
+ paths: compiledPaths,
331
+ };
332
+ });
333
+
334
+ const moduleMaps = flatten(await Promise.all(moduleMapsPromise));
335
+
336
+ const contents = generateComponentLink(moduleMaps);
337
+ return this.preview.writeLinkContents(contents, this.getComponentOutputPath(capsule), 'preview');
338
+ // return flatten(moduleMaps);
339
+ }
34
340
  }
@@ -5,11 +5,12 @@ import { ComponentMap } from '@teambit/component';
5
5
  import { Compiler } from '@teambit/compiler';
6
6
  import { AbstractVinyl } from '@teambit/legacy/dist/consumer/component/sources';
7
7
  import { Capsule } from '@teambit/isolator';
8
- import { BuildContext, ComponentResult } from '@teambit/builder';
9
- import { BundlerResult, BundlerContext } from '@teambit/bundler';
10
- import { BundlingStrategy } from '../bundling-strategy';
8
+ import { ComponentResult } from '@teambit/builder';
9
+ import { BundlerContext, BundlerHtmlConfig, BundlerResult } from '@teambit/bundler';
10
+ import type { BundlingStrategy, ComputeTargetsContext } from '../bundling-strategy';
11
11
  import { PreviewDefinition } from '../preview-definition';
12
12
  import { PreviewMain } from '../preview.main.runtime';
13
+ import { html } from '../webpack';
13
14
 
14
15
  /**
15
16
  * bundles all components in a given env into the same bundle.
@@ -19,19 +20,31 @@ export class EnvBundlingStrategy implements BundlingStrategy {
19
20
 
20
21
  constructor(private preview: PreviewMain) {}
21
22
 
22
- async computeTargets(context: BuildContext, previewDefs: PreviewDefinition[]) {
23
+ async computeTargets(context: ComputeTargetsContext, previewDefs: PreviewDefinition[]) {
23
24
  const outputPath = this.getOutputPath(context);
24
25
  if (!existsSync(outputPath)) mkdirpSync(outputPath);
26
+ const htmlConfig = this.generateHtmlConfig({ dev: context.dev });
25
27
 
26
28
  return [
27
29
  {
28
30
  entries: await this.computePaths(outputPath, previewDefs, context),
31
+ html: [htmlConfig],
29
32
  components: context.components,
30
33
  outputPath,
31
34
  },
32
35
  ];
33
36
  }
34
37
 
38
+ private generateHtmlConfig(options: { dev?: boolean }): BundlerHtmlConfig {
39
+ const config = {
40
+ title: 'Preview',
41
+ templateContent: html('Preview'),
42
+ cache: false,
43
+ minify: options?.dev ?? true,
44
+ };
45
+ return config;
46
+ }
47
+
35
48
  async computeResults(context: BundlerContext, results: BundlerResult[]) {
36
49
  const result = results[0];
37
50
 
@@ -53,7 +66,7 @@ export class EnvBundlingStrategy implements BundlingStrategy {
53
66
  };
54
67
  }
55
68
 
56
- private getArtifactDef(context: BuildContext) {
69
+ private getArtifactDef(context: ComputeTargetsContext) {
57
70
  // eslint-disable-next-line @typescript-eslint/prefer-as-const
58
71
  const env: 'env' = 'env';
59
72
  const rootDir = this.getDirName(context);
@@ -68,21 +81,25 @@ export class EnvBundlingStrategy implements BundlingStrategy {
68
81
  ];
69
82
  }
70
83
 
71
- getDirName(context: BuildContext) {
84
+ getDirName(context: ComputeTargetsContext) {
72
85
  const envName = context.id.replace('/', '__');
73
86
  return `${envName}-preview`;
74
87
  }
75
88
 
76
- private getOutputPath(context: BuildContext) {
89
+ private getOutputPath(context: ComputeTargetsContext) {
77
90
  return resolve(`${context.capsuleNetwork.capsulesRootDir}/${this.getDirName(context)}`);
78
91
  }
79
92
 
80
- private getPaths(context: BuildContext, files: AbstractVinyl[], capsule: Capsule) {
93
+ private getPaths(context: ComputeTargetsContext, files: AbstractVinyl[], capsule: Capsule) {
81
94
  const compiler: Compiler = context.env.getCompiler();
82
95
  return files.map((file) => join(capsule.path, compiler.getDistPathBySrcPath(file.relative)));
83
96
  }
84
97
 
85
- private async computePaths(outputPath: string, defs: PreviewDefinition[], context: BuildContext): Promise<string[]> {
98
+ private async computePaths(
99
+ outputPath: string,
100
+ defs: PreviewDefinition[],
101
+ context: ComputeTargetsContext
102
+ ): Promise<string[]> {
86
103
  const previewMain = await this.preview.writePreviewRuntime(context);
87
104
  const moduleMapsPromise = defs.map(async (previewDef) => {
88
105
  const moduleMap = await previewDef.getModuleMap(context.components);
@@ -102,7 +119,8 @@ export class EnvBundlingStrategy implements BundlingStrategy {
102
119
  previewDef.prefix,
103
120
  paths,
104
121
  previewDef.renderTemplatePath ? await previewDef.renderTemplatePath(context) : undefined,
105
- outputPath
122
+ outputPath,
123
+ false
106
124
  );
107
125
 
108
126
  const files = flatten(paths.toArray().map(([, file]) => file)).concat([link]);
@@ -0,0 +1,19 @@
1
+ import { toWindowsCompatiblePath } from '@teambit/toolbox.path.to-windows-compatible-path';
2
+
3
+ export type ModuleVar = {
4
+ prefix: string;
5
+ paths: string[];
6
+ };
7
+
8
+ export function generateComponentLink(modules: ModuleVar[]): string {
9
+ return `${modules
10
+ .map((moduleVar) => {
11
+ return `export const ${moduleVar.prefix} = [${moduleVar.paths
12
+ .map((path) => `require('${toWindowsCompatiblePath(path)}')`)
13
+ .join(', ')}]`;
14
+
15
+ // return `export { * as ${moduleVar.prefix} } from '${toWindowsCompatiblePath(moduleVar.paths)}'`;
16
+ })
17
+ .join('\n')}
18
+ `;
19
+ }
@@ -9,6 +9,8 @@ export type PreviewModule<T = any> = {
9
9
  mainModule: {
10
10
  default: (...args: any[]) => void;
11
11
  };
12
+
13
+ isSplitComponentBundle?: boolean
12
14
  };
13
15
 
14
16
  /** single preview module, e.g. compositions file */
@@ -0,0 +1,22 @@
1
+ /** html template for Previews (docs, compositions, etc) */
2
+ export function html(title: string) {
3
+ return `
4
+ <!DOCTYPE html>
5
+ <html lang="en">
6
+ <head>
7
+ <meta charset="utf-8">
8
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
9
+ <title>${title}</title>
10
+ <script>
11
+ // Allow to use react dev-tools inside the examples
12
+ try { window.__REACT_DEVTOOLS_GLOBAL_HOOK__ = window.parent.__REACT_DEVTOOLS_GLOBAL_HOOK__; } catch {}
13
+ </script>
14
+ <!-- minimal css resets -->
15
+ <style> html { height: 100%; } body { margin: 0; height: 100%; } #root { height: 100%; } </style>
16
+ </head>
17
+ <body>
18
+ <div id="root"></div>
19
+ </body>
20
+ </html>
21
+ `;
22
+ }
@@ -0,0 +1 @@
1
+ export { html } from './html';