@teambit/react 0.0.806 → 0.0.809

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 (46) hide show
  1. package/apps/web/compute-results.ts +3 -1
  2. package/apps/web/react-app-options.ts +5 -0
  3. package/apps/web/react-build-result.ts +1 -0
  4. package/apps/web/react.app-type.ts +1 -0
  5. package/apps/web/react.application.ts +61 -83
  6. package/apps/web/webpack/mutators.ts +68 -0
  7. package/apps/web/webpack/webpack.app.ssr.config.ts +24 -0
  8. package/artifacts/__bit_junit.xml +2 -2
  9. package/artifacts/env-template/public/{486.b4b503d786c3da312ae2.js → 879.bf6ddc62bb1cf07420f2.js} +2 -2
  10. package/artifacts/env-template/public/assets-manifest.json +12 -12
  11. package/artifacts/env-template/public/{compositions.70af3ab69b596fbcea59.js → compositions.0ae810b0436ec8173f05.js} +1 -1
  12. package/artifacts/env-template/public/compositions.html +1 -1
  13. package/artifacts/env-template/public/overview.1adece7f0bbabd5b25d4.js +1 -0
  14. package/artifacts/env-template/public/overview.html +1 -1
  15. package/artifacts/env-template/public/{peers.3e4ebdb2b1709b453faa.js → peers.9b8b9795a8f5501080cc.js} +1 -1
  16. package/artifacts/env-template/public/{preview-root.d61559bc7b06d0456acb.js → preview-root.c4f3db9b6c2c58a13430.js} +1 -1
  17. package/artifacts/env-template/public/static/css/{486.f6840c3e.css → 879.f6840c3e.css} +0 -0
  18. package/artifacts/preview/teambit_react_react-preview.js +1 -1
  19. package/{compositions-1659497571327.js → compositions-1659756525406.js} +0 -0
  20. package/dist/apps/web/compute-results.d.ts +2 -1
  21. package/dist/apps/web/compute-results.js +3 -1
  22. package/dist/apps/web/compute-results.js.map +1 -1
  23. package/dist/apps/web/react-app-options.d.ts +4 -0
  24. package/dist/apps/web/react-app-options.js.map +1 -1
  25. package/dist/apps/web/react-build-result.d.ts +1 -0
  26. package/dist/apps/web/react-build-result.js.map +1 -1
  27. package/dist/apps/web/react.app-type.js +1 -1
  28. package/dist/apps/web/react.app-type.js.map +1 -1
  29. package/dist/apps/web/react.application.d.ts +7 -3
  30. package/dist/apps/web/react.application.js +62 -95
  31. package/dist/apps/web/react.application.js.map +1 -1
  32. package/dist/apps/web/webpack/mutators.d.ts +3 -0
  33. package/dist/apps/web/webpack/mutators.js +90 -0
  34. package/dist/apps/web/webpack/mutators.js.map +1 -1
  35. package/dist/apps/web/webpack/webpack.app.ssr.config.d.ts +6 -0
  36. package/dist/apps/web/webpack/webpack.app.ssr.config.js +29 -0
  37. package/dist/apps/web/webpack/webpack.app.ssr.config.js.map +1 -1
  38. package/dist/webpack/webpack.config.base.js +15 -1
  39. package/dist/webpack/webpack.config.base.js.map +1 -1
  40. package/{overview-1659497571327.js → overview-1659756525406.js} +0 -0
  41. package/package-tar/teambit-react-0.0.809.tgz +0 -0
  42. package/package.json +32 -30
  43. package/{preview-1659497571327.js → preview-1659756525406.js} +2 -2
  44. package/webpack/webpack.config.base.ts +2 -1
  45. package/artifacts/env-template/public/overview.a0492e6adc2d378a78cf.js +0 -1
  46. package/package-tar/teambit-react-0.0.806.tgz +0 -0
@@ -3,15 +3,17 @@ import { ReactAppBuildResult } from './react-build-result';
3
3
 
4
4
  type resultsOptions = {
5
5
  publicDir: string;
6
+ ssrPublicDir?: string;
6
7
  };
7
8
  export async function computeResults(
8
9
  results: BundlerResult[],
9
- { publicDir }: resultsOptions
10
+ { publicDir, ssrPublicDir }: resultsOptions
10
11
  ): Promise<ReactAppBuildResult> {
11
12
  const result = results[0];
12
13
 
13
14
  return {
14
15
  publicDir,
16
+ ssrPublicDir,
15
17
  errors: result.errors,
16
18
  warnings: result.warnings,
17
19
  };
@@ -82,6 +82,11 @@ export type ReactAppOptions = {
82
82
  */
83
83
  bundler?: Bundler;
84
84
 
85
+ /**
86
+ * instance of serverside bundler to use. default is Webpack.
87
+ */
88
+ ssrBundler?: Bundler;
89
+
85
90
  /**
86
91
  * instance of dev server to use. default is Webpack.
87
92
  */
@@ -6,4 +6,5 @@ export type ReactAppBuildResult = {
6
6
  * when using ssr, public dir is undefined.
7
7
  */
8
8
  publicDir?: string;
9
+ ssrPublicDir?: string;
9
10
  } & AppBuildResult;
@@ -16,6 +16,7 @@ export class ReactAppType implements ApplicationType<ReactAppOptions> {
16
16
  this.reactEnv,
17
17
  options.prerender,
18
18
  options.bundler,
19
+ options.ssrBundler,
19
20
  options.devServer,
20
21
  options.webpackTransformers,
21
22
  options.deploy,
@@ -3,8 +3,7 @@ import { Application, AppContext, AppBuildContext, AppResult } from '@teambit/ap
3
3
  import type { Bundler, DevServer, BundlerContext, DevServerContext, BundlerHtmlConfig } from '@teambit/bundler';
4
4
  import { Port } from '@teambit/toolbox.network.get-port';
5
5
  import type { Logger } from '@teambit/logger';
6
- import { remove } from 'lodash';
7
- import TerserPlugin from 'terser-webpack-plugin';
6
+ import compact from 'lodash.compact';
8
7
  import { WebpackConfigTransformer } from '@teambit/webpack';
9
8
  import { BitError } from '@teambit/bit-error';
10
9
  import { ReactEnv } from '../../react.env';
@@ -14,8 +13,8 @@ import { ReactAppPrerenderOptions } from './react-app-options';
14
13
  import { html } from '../../webpack';
15
14
  import { ReactDeployContext } from '.';
16
15
  import { computeResults } from './compute-results';
17
- import { clientConfig, ssrConfig, calcOutputPath } from './webpack/webpack.app.ssr.config';
18
- import { addDevServer, setOutput } from './webpack/mutators';
16
+ import { clientConfig, ssrConfig, calcOutputPath, ssrBuildConfig, buildConfig } from './webpack/webpack.app.ssr.config';
17
+ import { addDevServer, setOutput, replaceTerserPlugin } from './webpack/mutators';
19
18
  import { createExpressSsr, loadSsrApp, parseAssets } from './ssr/ssr-express';
20
19
 
21
20
  export class ReactApp implements Application {
@@ -27,6 +26,7 @@ export class ReactApp implements Application {
27
26
  private reactEnv: ReactEnv,
28
27
  readonly prerender?: ReactAppPrerenderOptions,
29
28
  readonly bundler?: Bundler,
29
+ readonly ssrBundler?: Bundler,
30
30
  readonly devServer?: DevServer,
31
31
  readonly transformers: WebpackConfigTransformer[] = [],
32
32
  readonly deploy?: (context: ReactDeployContext) => Promise<void>,
@@ -35,6 +35,7 @@ export class ReactApp implements Application {
35
35
  ) {}
36
36
  readonly applicationType = 'react-common-js';
37
37
  readonly dir = 'public';
38
+ readonly ssrDir = 'ssr';
38
39
 
39
40
  async run(context: AppContext): Promise<number> {
40
41
  const [from, to] = this.portRange;
@@ -163,23 +164,71 @@ export class ReactApp implements Application {
163
164
  const bundler = await this.getBundler(context);
164
165
  const bundleResult = await bundler.run();
165
166
 
166
- return computeResults(bundleResult, { publicDir: `${this.getPublicDir(context.artifactsDir)}/${this.dir}` });
167
+ if (this.ssr) {
168
+ const bunlder = await this.getSsrBundler(context);
169
+ await bunlder.run();
170
+ }
171
+
172
+ return computeResults(bundleResult, {
173
+ publicDir: `${this.getPublicDir(context.artifactsDir)}/${this.dir}`,
174
+ ssrPublicDir: this.ssr ? `${this.getPublicDir(context.artifactsDir)}/${this.ssrDir}` : undefined,
175
+ });
167
176
  }
168
177
 
169
178
  private getBundler(context: AppBuildContext) {
170
179
  if (this.bundler) return this.bundler;
171
180
  return this.getDefaultBundler(context);
172
181
  }
173
-
182
+
183
+ private getSsrBundler(context: AppBuildContext) {
184
+ if (this.ssrBundler) return this.ssrBundler;
185
+ return this.getDefaultSsrBundler(context);
186
+ }
187
+
174
188
  private async getDefaultBundler(context: AppBuildContext) {
175
189
  const { capsule } = context;
176
- const reactEnv: ReactEnv = context.env as ReactEnv;
177
190
  const publicDir = this.getPublicDir(context.artifactsDir);
178
191
  const outputPath = join(capsule.path, publicDir);
192
+
193
+ const bundlerContext = await this.getBuildContext(context, { outputPath });
194
+ const transformers: WebpackConfigTransformer[] = compact([
195
+ (configMutator) => configMutator.merge(buildConfig({ outputPath: join(outputPath, this.dir) })),
196
+ (config) => {
197
+ if (this.prerender) config.addPlugin(prerenderPlugin(this.prerender));
198
+ return config;
199
+ },
200
+ replaceTerserPlugin({ prerender: !!this.prerender }),
201
+ ...this.transformers,
202
+ ]);
203
+
204
+ const reactEnv = context.env as ReactEnv;
205
+ const bundler: Bundler = await reactEnv.getBundler(bundlerContext, transformers);
206
+ return bundler;
207
+ }
208
+
209
+ private async getDefaultSsrBundler(context: AppBuildContext) {
210
+ const { capsule } = context;
211
+ const publicDir = this.getPublicDir(context.artifactsDir);
212
+ const outputPath = join(capsule.path, publicDir);
213
+
214
+ const bundlerContext = await this.getBuildContext(context, { outputPath });
215
+ const transformers: WebpackConfigTransformer[] = compact([
216
+ (configMutator) => configMutator.merge(ssrBuildConfig({ outputPath: join(outputPath, this.ssrDir) })),
217
+ replaceTerserPlugin({ prerender: !!this.prerender }),
218
+ ...this.transformers,
219
+ ]);
220
+
221
+ const reactEnv = context.env as ReactEnv;
222
+ const bundler: Bundler = await reactEnv.getBundler(bundlerContext, transformers);
223
+ return bundler;
224
+ }
225
+
226
+ private async getBuildContext(context: AppBuildContext, { outputPath }: { outputPath: string }) {
227
+ const { capsule } = context;
228
+ const reactEnv = context.env as ReactEnv;
179
229
  const { distDir } = reactEnv.getCompiler();
180
- const targetEntries = Array.isArray(this.entry) ? this.entry : await this.entry(`${capsule.path}/${distDir}`);
230
+ const targetEntries = await this.getEntries(`${capsule.path}/${distDir}`);
181
231
  const entries = targetEntries.map((entry) => require.resolve(`${capsule.path}/${distDir}/${basename(entry)}`));
182
- const staticDir = join(outputPath, this.dir);
183
232
 
184
233
  const bundlerContext: BundlerContext = Object.assign(context, {
185
234
  targets: [
@@ -200,87 +249,16 @@ export class ReactApp implements Application {
200
249
  },
201
250
  });
202
251
 
203
- const defaultTransformer: WebpackConfigTransformer = (configMutator) => {
204
- const config = configMutator.addTopLevel('output', {
205
- path: staticDir,
206
- publicPath: `/`,
207
- filename: '[name].[chunkhash].js',
208
- });
209
- if (this.prerender) config.addPlugin(prerenderPlugin(this.prerender));
210
- if (config.raw.optimization?.minimizer) {
211
- remove(config.raw.optimization?.minimizer, (minimizer) => {
212
- return minimizer.constructor.name === 'TerserPlugin';
213
- });
214
-
215
- config.raw.optimization?.minimizer.push(this.getESBuildConfig());
216
- }
217
-
218
- return config;
219
- };
220
- const transformers = [defaultTransformer, ...this.transformers];
221
- const bundler: Bundler = await reactEnv.getBundler(bundlerContext, transformers);
222
- return bundler;
252
+ return bundlerContext;
223
253
  }
224
- private getESBuildConfig = (isPrerendering = this.prerender) => {
225
- // We don't want to use esbuild in case of prerendering since the headless browser puppeteer doesn't support
226
- // the output of esbuild
227
-
228
- if (isPrerendering) {
229
- return new TerserPlugin({
230
- extractComments: false,
231
- terserOptions: {
232
- parse: {
233
- // We want terser to parse ecma 8 code. However, we don't want it
234
- // to apply any minification steps that turns valid ecma 5 code
235
- // into invalid ecma 5 code. This is why the 'compress' and 'output'
236
- // sections only apply transformations that are ecma 5 safe
237
- // https://github.com/facebook/create-react-app/pull/4234
238
- ecma: 8,
239
- },
240
- compress: {
241
- ecma: 5,
242
- warnings: false,
243
- // Disabled because of an issue with Uglify breaking seemingly valid code:
244
- // https://github.com/facebook/create-react-app/issues/2376
245
- // Pending further investigation:
246
- // https://github.com/mishoo/UglifyJS2/issues/2011
247
- comparisons: false,
248
- // Disabled because of an issue with Terser breaking valid code:
249
- // https://github.com/facebook/create-react-app/issues/5250
250
- // Pending further investigation:
251
- // https://github.com/terser-js/terser/issues/120
252
- inline: 2,
253
- },
254
- mangle: {
255
- safari10: true,
256
- },
257
- output: {
258
- ecma: 5,
259
- comments: false,
260
- // Turned on because emoji and regex is not minified properly using default
261
- // https://github.com/facebook/create-react-app/issues/2488
262
- ascii_only: true,
263
- },
264
- },
265
- });
266
- }
267
- return new TerserPlugin({
268
- minify: TerserPlugin.esbuildMinify,
269
- // `terserOptions` options will be passed to `esbuild`
270
- // Link to options - https://esbuild.github.io/api/#minify
271
- terserOptions: {
272
- minify: true,
273
- },
274
- });
275
- };
276
254
 
277
255
  private getPublicDir(artifactsDir: string) {
278
256
  return join(artifactsDir, this.applicationType, this.name);
279
257
  }
280
258
 
281
- async getEntries(): Promise<string[]> {
259
+ async getEntries(path?: string): Promise<string[]> {
282
260
  if (Array.isArray(this.entry)) return this.entry;
283
- return this.entry();
261
+ return this.entry(path);
284
262
  }
285
263
 
286
264
  async getSsrEntries(): Promise<string[]> {
@@ -1,4 +1,6 @@
1
1
  import { WebpackConfigMutator } from '@teambit/webpack';
2
+ import { remove } from 'lodash';
3
+ import TerserPlugin from 'terser-webpack-plugin';
2
4
 
3
5
  export function addDevServer(configMutator: WebpackConfigMutator) {
4
6
  return configMutator.addTopLevel('devServer', {
@@ -19,3 +21,69 @@ export function setOutput(configMutator: WebpackConfigMutator) {
19
21
 
20
22
  return configMutator;
21
23
  }
24
+
25
+ export function replaceTerserPlugin({ prerender = false }: { prerender: boolean }) {
26
+ return (configMutator: WebpackConfigMutator) => {
27
+ if (!configMutator.raw.optimization?.minimizer) return configMutator;
28
+
29
+ remove(configMutator.raw.optimization?.minimizer, (minimizer) => {
30
+ return minimizer.constructor.name === 'TerserPlugin';
31
+ });
32
+
33
+ const terserer = prerender ? CreateTerserPluginForPrerender() : CreateTerserPlugin();
34
+ configMutator.raw.optimization?.minimizer.push(terserer);
35
+
36
+ return configMutator;
37
+ };
38
+ }
39
+
40
+ function CreateTerserPlugin() {
41
+ return new TerserPlugin({
42
+ minify: TerserPlugin.esbuildMinify,
43
+ // `terserOptions` options will be passed to `esbuild`
44
+ // Link to options - https://esbuild.github.io/api/#minify
45
+ terserOptions: {
46
+ minify: true,
47
+ },
48
+ });
49
+ }
50
+
51
+ function CreateTerserPluginForPrerender() {
52
+ return new TerserPlugin({
53
+ extractComments: false,
54
+ terserOptions: {
55
+ parse: {
56
+ // We want terser to parse ecma 8 code. However, we don't want it
57
+ // to apply any minification steps that turns valid ecma 5 code
58
+ // into invalid ecma 5 code. This is why the 'compress' and 'output'
59
+ // sections only apply transformations that are ecma 5 safe
60
+ // https://github.com/facebook/create-react-app/pull/4234
61
+ ecma: 8,
62
+ },
63
+ compress: {
64
+ ecma: 5,
65
+ warnings: false,
66
+ // Disabled because of an issue with Uglify breaking seemingly valid code:
67
+ // https://github.com/facebook/create-react-app/issues/2376
68
+ // Pending further investigation:
69
+ // https://github.com/mishoo/UglifyJS2/issues/2011
70
+ comparisons: false,
71
+ // Disabled because of an issue with Terser breaking valid code:
72
+ // https://github.com/facebook/create-react-app/issues/5250
73
+ // Pending further investigation:
74
+ // https://github.com/terser-js/terser/issues/120
75
+ inline: 2,
76
+ },
77
+ mangle: {
78
+ safari10: true,
79
+ },
80
+ output: {
81
+ ecma: 5,
82
+ comments: false,
83
+ // Turned on because emoji and regex is not minified properly using default
84
+ // https://github.com/facebook/create-react-app/issues/2488
85
+ ascii_only: true,
86
+ },
87
+ },
88
+ });
89
+ }
@@ -35,3 +35,27 @@ export function ssrConfig(): Configuration {
35
35
  },
36
36
  };
37
37
  }
38
+
39
+ export function buildConfig({ outputPath }: { outputPath: string }): Configuration {
40
+ return {
41
+ output: {
42
+ path: outputPath,
43
+ publicPath: `/`,
44
+ filename: '[name].[chunkhash].js',
45
+ },
46
+ };
47
+ }
48
+
49
+ export function ssrBuildConfig({ outputPath }: { outputPath: string }): Configuration {
50
+ return {
51
+ target: 'node',
52
+ devtool: 'eval-cheap-source-map',
53
+
54
+ output: {
55
+ path: outputPath,
56
+ publicPath: `/`,
57
+ libraryTarget: 'commonjs',
58
+ filename: 'index.js',
59
+ },
60
+ };
61
+ }
@@ -1,6 +1,6 @@
1
1
  <?xml version="1.0" encoding="UTF-8"?>
2
2
  <testsuites>
3
- <testsuite name="teambit.react/react@0.0.806" timestamp="2022-08-03T03:54:25.377Z" tests="1" failures="0" errors="0" skipped="0">
4
- <testcase classname="index-file.spec.js" name="should match snapshot" time="0.18"/>
3
+ <testsuite name="teambit.react/react@0.0.809" timestamp="2022-08-06T03:50:57.914Z" tests="1" failures="0" errors="0" skipped="0">
4
+ <testcase classname="index-file.spec.js" name="should match snapshot" time="0.194"/>
5
5
  </testsuite>
6
6
  </testsuites>