@teambit/ui 0.0.568 → 0.0.569
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/compose.tsx +27 -0
- package/events/index.ts +1 -0
- package/events/ui-server-started-event.ts +14 -0
- package/exceptions/index.ts +2 -0
- package/exceptions/unknown-build-error.ts +5 -0
- package/exceptions/unknown-ui.ts +9 -0
- package/package-tar/teambit-ui-0.0.569.tgz +0 -0
- package/package.json +24 -39
- package/render-lifecycle.tsx +56 -0
- package/ssr/render-middleware.ts +129 -0
- package/ssr/request-browser.ts +86 -0
- package/ssr/request-server.ts +10 -0
- package/ssr/ssr-content.ts +9 -0
- package/start.cmd.tsx +93 -0
- package/types/asset.d.ts +29 -0
- package/types/style.d.ts +42 -0
- package/ui/client-context.tsx +28 -0
- package/ui-build.cmd.tsx +27 -0
- package/ui-root.tsx +59 -0
- package/ui.cli.rt.tsx +10 -0
- package/ui.ui.runtime.tsx +277 -0
- package/webpack/html.ts +24 -0
- package/webpack/postcss.config.ts +22 -0
- package/webpack/webpack.base.config.ts +392 -0
- package/webpack/webpack.browser.config.ts +125 -0
- package/webpack/webpack.dev.config.ts +338 -0
- package/webpack/webpack.ssr.config.ts +38 -0
package/compose.tsx
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import React, { ReactNode, ComponentType } from 'react';
|
|
2
|
+
|
|
3
|
+
type ComponentTuple<T = any> = [Component: ComponentType<T>, props?: T];
|
|
4
|
+
export type Wrapper<T = any> = ComponentType<T> | ComponentTuple<T>;
|
|
5
|
+
interface Props<T = any> {
|
|
6
|
+
/** Compose these components. Can be a ReactComponent, or a [ReactComponent, Props] tuple */
|
|
7
|
+
components: Wrapper<T>[];
|
|
8
|
+
children?: ReactNode;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* A react Component composer. equivalent to `(n+1) => <a[n+1]> <Compose(a[n]) /> </a[n+1]>`.
|
|
13
|
+
* Component can be a React Component, or a `[Component, { ...props }]` tuple.
|
|
14
|
+
*/
|
|
15
|
+
export function Compose(props: Props) {
|
|
16
|
+
const { components = [], children } = props;
|
|
17
|
+
|
|
18
|
+
const arrayified: ComponentTuple[] = components.map((tuple) => (Array.isArray(tuple) ? tuple : [tuple, undefined]));
|
|
19
|
+
|
|
20
|
+
return (
|
|
21
|
+
<>
|
|
22
|
+
{arrayified.reduceRight((acc, [Comp, forwardProps]) => {
|
|
23
|
+
return <Comp {...forwardProps}>{acc}</Comp>;
|
|
24
|
+
}, children)}
|
|
25
|
+
</>
|
|
26
|
+
);
|
|
27
|
+
}
|
package/events/index.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './ui-server-started-event';
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/* eslint-disable max-classes-per-file */
|
|
2
|
+
import { BitBaseEvent } from '@teambit/pubsub';
|
|
3
|
+
|
|
4
|
+
class UiServerStartedEventData {
|
|
5
|
+
constructor(readonly targetHost, readonly targetPort, readonly uiRoot) {}
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export class UiServerStartedEvent extends BitBaseEvent<UiServerStartedEventData> {
|
|
9
|
+
static readonly TYPE = 'ui-server-started';
|
|
10
|
+
|
|
11
|
+
constructor(readonly timestamp, readonly targetHost, readonly targetPort, readonly uiRoot) {
|
|
12
|
+
super(UiServerStartedEvent.TYPE, '0.0.1', timestamp, new UiServerStartedEventData(targetHost, targetPort, uiRoot));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@teambit/ui",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.569",
|
|
4
4
|
"homepage": "https://bit.dev/teambit/ui-foundation/ui",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"componentId": {
|
|
7
7
|
"scope": "teambit.ui-foundation",
|
|
8
8
|
"name": "ui",
|
|
9
|
-
"version": "0.0.
|
|
9
|
+
"version": "0.0.569"
|
|
10
10
|
},
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"lodash": "4.17.21",
|
|
@@ -53,28 +53,28 @@
|
|
|
53
53
|
"@teambit/base-ui.loaders.loader-ribbon": "1.0.0",
|
|
54
54
|
"@teambit/base-ui.theme.fonts.roboto": "1.0.0",
|
|
55
55
|
"@teambit/base-ui.theme.theme-provider": "1.0.1",
|
|
56
|
-
"@teambit/aspect-loader": "0.0.
|
|
57
|
-
"@teambit/toolbox.path.to-windows-compatible-path": "0.0.
|
|
58
|
-
"@teambit/ui-foundation.ui.hooks.use-data-query": "0.0.
|
|
59
|
-
"@teambit/logger": "0.0.
|
|
60
|
-
"@teambit/cli": "0.0.
|
|
61
|
-
"@teambit/ui-foundation.cli.ui-server-console": "0.0.
|
|
62
|
-
"@teambit/bundler": "0.0.
|
|
63
|
-
"@teambit/component": "0.0.
|
|
64
|
-
"@teambit/express": "0.0.
|
|
65
|
-
"@teambit/graphql": "0.0.
|
|
66
|
-
"@teambit/toolbox.network.get-port": "0.0.
|
|
67
|
-
"@teambit/aspect": "0.0.
|
|
68
|
-
"@teambit/cache": "0.0.
|
|
69
|
-
"@teambit/pubsub": "0.0.
|
|
70
|
-
"@teambit/react-router": "0.0.
|
|
71
|
-
"@teambit/ui-foundation.ui.rendering.html": "0.0.
|
|
56
|
+
"@teambit/aspect-loader": "0.0.569",
|
|
57
|
+
"@teambit/toolbox.path.to-windows-compatible-path": "0.0.469",
|
|
58
|
+
"@teambit/ui-foundation.ui.hooks.use-data-query": "0.0.473",
|
|
59
|
+
"@teambit/logger": "0.0.481",
|
|
60
|
+
"@teambit/cli": "0.0.395",
|
|
61
|
+
"@teambit/ui-foundation.cli.ui-server-console": "0.0.474",
|
|
62
|
+
"@teambit/bundler": "0.0.569",
|
|
63
|
+
"@teambit/component": "0.0.569",
|
|
64
|
+
"@teambit/express": "0.0.485",
|
|
65
|
+
"@teambit/graphql": "0.0.569",
|
|
66
|
+
"@teambit/toolbox.network.get-port": "0.0.99",
|
|
67
|
+
"@teambit/aspect": "0.0.569",
|
|
68
|
+
"@teambit/cache": "0.0.481",
|
|
69
|
+
"@teambit/pubsub": "0.0.569",
|
|
70
|
+
"@teambit/react-router": "0.0.569",
|
|
71
|
+
"@teambit/ui-foundation.ui.rendering.html": "0.0.55",
|
|
72
72
|
"@teambit/design.theme.icons-font": "1.0.2",
|
|
73
73
|
"@teambit/design.ui.tooltip": "0.0.352",
|
|
74
|
-
"@teambit/ui-foundation.ui.global-loader": "0.0.
|
|
75
|
-
"@teambit/webpack.modules.generate-style-loaders": "0.0.
|
|
76
|
-
"@teambit/webpack.modules.style-regexps": "0.0.
|
|
77
|
-
"@teambit/webpack": "0.0.
|
|
74
|
+
"@teambit/ui-foundation.ui.global-loader": "0.0.472",
|
|
75
|
+
"@teambit/webpack.modules.generate-style-loaders": "0.0.89",
|
|
76
|
+
"@teambit/webpack.modules.style-regexps": "0.0.118",
|
|
77
|
+
"@teambit/webpack": "0.0.569"
|
|
78
78
|
},
|
|
79
79
|
"devDependencies": {
|
|
80
80
|
"@types/react": "^17.0.8",
|
|
@@ -96,7 +96,7 @@
|
|
|
96
96
|
},
|
|
97
97
|
"peerDependencies": {
|
|
98
98
|
"@apollo/client": "^3.0.0",
|
|
99
|
-
"@teambit/legacy": "1.0.
|
|
99
|
+
"@teambit/legacy": "1.0.181",
|
|
100
100
|
"react-dom": "^16.8.0 || ^17.0.0",
|
|
101
101
|
"react": "^16.8.0 || ^17.0.0"
|
|
102
102
|
},
|
|
@@ -141,27 +141,12 @@
|
|
|
141
141
|
"react": "-"
|
|
142
142
|
},
|
|
143
143
|
"peerDependencies": {
|
|
144
|
-
"@teambit/legacy": "1.0.
|
|
144
|
+
"@teambit/legacy": "1.0.181",
|
|
145
145
|
"react-dom": "^16.8.0 || ^17.0.0",
|
|
146
146
|
"react": "^16.8.0 || ^17.0.0"
|
|
147
147
|
}
|
|
148
148
|
}
|
|
149
149
|
},
|
|
150
|
-
"files": [
|
|
151
|
-
"dist",
|
|
152
|
-
"!dist/tsconfig.tsbuildinfo",
|
|
153
|
-
"**/*.md",
|
|
154
|
-
"**/*.mdx",
|
|
155
|
-
"**/*.js",
|
|
156
|
-
"**/*.json",
|
|
157
|
-
"**/*.sass",
|
|
158
|
-
"**/*.scss",
|
|
159
|
-
"**/*.less",
|
|
160
|
-
"**/*.css",
|
|
161
|
-
"**/*.css",
|
|
162
|
-
"**/*.jpeg",
|
|
163
|
-
"**/*.gif"
|
|
164
|
-
],
|
|
165
150
|
"private": false,
|
|
166
151
|
"engines": {
|
|
167
152
|
"node": ">=12.22.0"
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import { ReactNode, ComponentType } from 'react';
|
|
2
|
+
import { BrowserData } from './ssr/request-browser';
|
|
3
|
+
import { RequestServer } from './ssr/request-server';
|
|
4
|
+
import { ContextProps } from './ui.ui.runtime';
|
|
5
|
+
|
|
6
|
+
export type RenderLifecycle<RenderCtx = any, Serialized = any> = {
|
|
7
|
+
/**
|
|
8
|
+
* Initialize a context state for this specific rendering.
|
|
9
|
+
* Context state will only be available to the current Aspect, in the other hooks, as well as a prop to the react context component.
|
|
10
|
+
*/
|
|
11
|
+
serverInit?: (state: {
|
|
12
|
+
browser?: BrowserData;
|
|
13
|
+
server?: RequestServer;
|
|
14
|
+
}) => RenderCtx | void | undefined | Promise<RenderCtx | void | undefined>;
|
|
15
|
+
/**
|
|
16
|
+
* Executes before running ReactDOM.renderToString(). Return value will replace the existing context state.
|
|
17
|
+
*/
|
|
18
|
+
onBeforeRender?: (
|
|
19
|
+
ctx: RenderCtx,
|
|
20
|
+
app: ReactNode
|
|
21
|
+
) => RenderCtx | void | undefined | Promise<RenderCtx | void | undefined>;
|
|
22
|
+
/**
|
|
23
|
+
* Produce html assets. Runs after the body is rendered, and before rendering the final html.
|
|
24
|
+
* @returns
|
|
25
|
+
* json: will be rendered to the dom as a `<script type="json"/>`.
|
|
26
|
+
* More assets will be available in the future.
|
|
27
|
+
*/
|
|
28
|
+
serialize?: (ctx: RenderCtx, app: ReactNode) => { json: string } | Promise<{ json: string }> | undefined;
|
|
29
|
+
/**
|
|
30
|
+
* Converts serialized data from raw string back to structured data.
|
|
31
|
+
* @example deserialize: (data) => { const parsed = JSON.parse(data); return { analytics: new AnalyticsService(parsed); } }
|
|
32
|
+
*/
|
|
33
|
+
deserialize?: (data?: string) => Serialized;
|
|
34
|
+
/**
|
|
35
|
+
* Initialize the context state for client side rendering.
|
|
36
|
+
* Context state will only be available to the current Aspect, in the other hooks, as well as a prop to the react context component.
|
|
37
|
+
*/
|
|
38
|
+
browserInit?: (deserializedData: Serialized) => RenderCtx | void | undefined | Promise<RenderCtx | void | undefined>;
|
|
39
|
+
/**
|
|
40
|
+
* Executes before running ReactDOM.hydrate() (or .render() in case server side rendering is skipped). Receives the context produced by `deserialize()`
|
|
41
|
+
*/
|
|
42
|
+
onBeforeHydrate?: (
|
|
43
|
+
context: RenderCtx,
|
|
44
|
+
app: ReactNode
|
|
45
|
+
) => RenderCtx | void | undefined | Promise<RenderCtx | void | undefined>;
|
|
46
|
+
/**
|
|
47
|
+
* Executes after browser rendering is complete. Receives context from the previous steps.
|
|
48
|
+
* @example onHydrate: (ref, { analytics }) => { analytics.reportPageView() }
|
|
49
|
+
*/
|
|
50
|
+
onHydrate?: (context: RenderCtx, ref: HTMLElement | null) => void;
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Wraps dom with a context. Will receive render context, produced by `onBeforeRender()` (at server-side) or `deserialize()` (at the browser)
|
|
54
|
+
*/
|
|
55
|
+
reactContext?: ComponentType<ContextProps<RenderCtx>>;
|
|
56
|
+
};
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import type { Assets } from '@teambit/ui-foundation.ui.rendering.html';
|
|
2
|
+
import { Request, Response, NextFunction } from 'express';
|
|
3
|
+
import path from 'path';
|
|
4
|
+
import * as fs from 'fs-extra';
|
|
5
|
+
import type { Logger } from '@teambit/logger';
|
|
6
|
+
import { requestToObj } from './request-browser';
|
|
7
|
+
import { SsrContent } from './ssr-content';
|
|
8
|
+
|
|
9
|
+
const denyList = /^\/favicon.ico$/;
|
|
10
|
+
|
|
11
|
+
type ssrRenderProps = {
|
|
12
|
+
root: string;
|
|
13
|
+
port: number;
|
|
14
|
+
title: string;
|
|
15
|
+
logger: Logger;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
type ManifestFile = {
|
|
19
|
+
files?: Record<string, string>;
|
|
20
|
+
entrypoints?: string[];
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export async function createSsrMiddleware({ root, port, title, logger }: ssrRenderProps) {
|
|
24
|
+
const runtime = await loadRuntime(root, { logger });
|
|
25
|
+
if (!runtime) return undefined;
|
|
26
|
+
|
|
27
|
+
const { render } = runtime;
|
|
28
|
+
const assets = { ...runtime.assets, title };
|
|
29
|
+
|
|
30
|
+
return async function serverRenderMiddleware(req: Request, res: Response, next: NextFunction) {
|
|
31
|
+
const { query, url } = req;
|
|
32
|
+
|
|
33
|
+
const browser = requestToObj(req, port);
|
|
34
|
+
|
|
35
|
+
if (denyList.test(url)) {
|
|
36
|
+
logger.debug(`[ssr] skipping static denyList file ${url}`);
|
|
37
|
+
next();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
if (query.rendering === 'client') {
|
|
42
|
+
logger.debug(`[ssr] skipping ${url}`);
|
|
43
|
+
next();
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
logger.debug(`[ssr] ${req.method} ${url}`);
|
|
48
|
+
const server = { port, request: req, response: res };
|
|
49
|
+
const props: SsrContent = { assets, browser, server };
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
const rendered = await render(props);
|
|
53
|
+
res.set('Cache-Control', 'no-cache');
|
|
54
|
+
res.send(rendered);
|
|
55
|
+
logger.debug(`[ssr] success '${url}'`);
|
|
56
|
+
} catch (e: any) {
|
|
57
|
+
logger.error(`[ssr] failed at '${url}'`, e);
|
|
58
|
+
next();
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async function loadRuntime(root: string, { logger }: { logger: Logger }) {
|
|
64
|
+
let render: (...arg: any[]) => any;
|
|
65
|
+
let assets: Assets | undefined;
|
|
66
|
+
|
|
67
|
+
try {
|
|
68
|
+
const entryFilepath = path.join(root, 'ssr', 'index.js');
|
|
69
|
+
if (!fs.existsSync(entryFilepath)) {
|
|
70
|
+
logger.warn(`[ssr] - Skipping setup - failed finding ssr bundle at "${entryFilepath}"`);
|
|
71
|
+
return undefined;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
const manifestFilepath = path.join(root, 'asset-manifest.json');
|
|
75
|
+
if (!fs.existsSync(manifestFilepath)) {
|
|
76
|
+
logger.warn('[ssr] - Skipping setup (cannot find asset manifest file)');
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
assets = await parseManifest(manifestFilepath);
|
|
81
|
+
if (!assets) {
|
|
82
|
+
logger.warn('[ssr] - Skipping setup (failed parsing assets manifest)');
|
|
83
|
+
return undefined;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
const imported = await import(entryFilepath);
|
|
87
|
+
render = imported?.render;
|
|
88
|
+
|
|
89
|
+
if (!render || typeof render !== 'function') {
|
|
90
|
+
logger.warn('[ssr] - index file does not export a render() function. Skipping setup.');
|
|
91
|
+
return undefined;
|
|
92
|
+
}
|
|
93
|
+
} catch (e: any) {
|
|
94
|
+
logger.error(e);
|
|
95
|
+
return undefined;
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
return {
|
|
99
|
+
render,
|
|
100
|
+
assets,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
async function parseManifest(filepath: string, logger?: Logger) {
|
|
105
|
+
try {
|
|
106
|
+
const file = await fs.readFile(filepath);
|
|
107
|
+
logger?.debug('[ssr] - ✓ aread manifest file');
|
|
108
|
+
const contents = file.toString();
|
|
109
|
+
const parsed: ManifestFile = JSON.parse(contents);
|
|
110
|
+
logger?.debug('[ssr] - ✓ prased manifest file', parsed);
|
|
111
|
+
const assets = getAssets(parsed);
|
|
112
|
+
logger?.debug('[ssr] - ✓ extracted data from manifest file', assets);
|
|
113
|
+
|
|
114
|
+
return assets;
|
|
115
|
+
} catch (e: any) {
|
|
116
|
+
logger?.error('[ssr] - error parsing asset manifest', e);
|
|
117
|
+
process.exit();
|
|
118
|
+
return undefined;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function getAssets(manifest: ManifestFile) {
|
|
123
|
+
const assets: Assets = { css: [], js: [] };
|
|
124
|
+
|
|
125
|
+
assets.css = manifest.entrypoints?.filter((x) => x.endsWith('css')).map((x) => path.join('/', x));
|
|
126
|
+
assets.js = manifest.entrypoints?.filter((x) => x.endsWith('js')).map((x) => path.join('/', x));
|
|
127
|
+
|
|
128
|
+
return assets;
|
|
129
|
+
}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { IncomingHttpHeaders } from 'http';
|
|
2
|
+
import type { Request } from 'express';
|
|
3
|
+
|
|
4
|
+
export type ParsedQuery = { [key: string]: undefined | string | string[] | ParsedQuery | ParsedQuery[] };
|
|
5
|
+
|
|
6
|
+
export type BrowserData = {
|
|
7
|
+
connection: {
|
|
8
|
+
secure: boolean;
|
|
9
|
+
headers: IncomingHttpHeaders;
|
|
10
|
+
body: any;
|
|
11
|
+
};
|
|
12
|
+
/**
|
|
13
|
+
* isomorphic location object, resembling the browser's window.location
|
|
14
|
+
*/
|
|
15
|
+
location: {
|
|
16
|
+
/** hostname + port
|
|
17
|
+
* @example localhost:3000
|
|
18
|
+
*/
|
|
19
|
+
host: string;
|
|
20
|
+
/**
|
|
21
|
+
* @example localhost
|
|
22
|
+
*/
|
|
23
|
+
hostname: string;
|
|
24
|
+
/** full url
|
|
25
|
+
* @example http://localhost:3000/components?q=button
|
|
26
|
+
*/
|
|
27
|
+
href: string;
|
|
28
|
+
/** full url without query
|
|
29
|
+
* @example http://localhost:3000/components
|
|
30
|
+
*/
|
|
31
|
+
origin: string;
|
|
32
|
+
/**
|
|
33
|
+
* @example /component
|
|
34
|
+
*/
|
|
35
|
+
pathname: string;
|
|
36
|
+
/**
|
|
37
|
+
* @example 3000
|
|
38
|
+
*/
|
|
39
|
+
port: number;
|
|
40
|
+
/**
|
|
41
|
+
* @example http
|
|
42
|
+
*/
|
|
43
|
+
protocol: string;
|
|
44
|
+
/**
|
|
45
|
+
* parsed search params
|
|
46
|
+
* @example { one: 1, two: [2,3]}
|
|
47
|
+
*/
|
|
48
|
+
query: ParsedQuery;
|
|
49
|
+
/**
|
|
50
|
+
* full resource path, including query, without hostname
|
|
51
|
+
* @example /components?q=button
|
|
52
|
+
*/
|
|
53
|
+
url: string;
|
|
54
|
+
};
|
|
55
|
+
cookie?: string;
|
|
56
|
+
};
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* extract relevant information from Express request.
|
|
60
|
+
*/
|
|
61
|
+
export function requestToObj(req: Request, port: number) {
|
|
62
|
+
// apparently port is not readily available in request.
|
|
63
|
+
|
|
64
|
+
const browser: BrowserData = {
|
|
65
|
+
connection: {
|
|
66
|
+
secure: req.secure,
|
|
67
|
+
headers: req.headers,
|
|
68
|
+
body: req.body,
|
|
69
|
+
},
|
|
70
|
+
// trying to match to browser.location
|
|
71
|
+
location: {
|
|
72
|
+
host: `${req.hostname}:${port}`,
|
|
73
|
+
hostname: req.hostname,
|
|
74
|
+
href: `${req.protocol}://${req.hostname}:${port}${req.url}`,
|
|
75
|
+
origin: `${req.protocol}://${req.hostname}:${port}`,
|
|
76
|
+
pathname: req.path,
|
|
77
|
+
port,
|
|
78
|
+
protocol: `${req.protocol}:`,
|
|
79
|
+
query: req.query,
|
|
80
|
+
url: req.url,
|
|
81
|
+
},
|
|
82
|
+
cookie: req.header('Cookie'),
|
|
83
|
+
};
|
|
84
|
+
|
|
85
|
+
return browser;
|
|
86
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { Assets } from '@teambit/ui-foundation.ui.rendering.html';
|
|
2
|
+
import { BrowserData } from './request-browser';
|
|
3
|
+
import { RequestServer } from './request-server';
|
|
4
|
+
|
|
5
|
+
export type SsrContent = {
|
|
6
|
+
assets?: Assets;
|
|
7
|
+
browser?: BrowserData;
|
|
8
|
+
server?: RequestServer;
|
|
9
|
+
};
|
package/start.cmd.tsx
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import open from 'open';
|
|
3
|
+
import { Command, CommandOptions } from '@teambit/cli';
|
|
4
|
+
import { Logger } from '@teambit/logger';
|
|
5
|
+
import { UIServerConsole } from '@teambit/ui-foundation.cli.ui-server-console';
|
|
6
|
+
import type { UiMain } from './ui.main.runtime';
|
|
7
|
+
|
|
8
|
+
type StartArgs = [uiName: string, userPattern: string];
|
|
9
|
+
type StartFlags = {
|
|
10
|
+
dev: boolean;
|
|
11
|
+
port: string;
|
|
12
|
+
rebuild: boolean;
|
|
13
|
+
verbose: boolean;
|
|
14
|
+
noBrowser: boolean;
|
|
15
|
+
skipCompilation: boolean;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export class StartCmd implements Command {
|
|
19
|
+
name = 'start [type] [pattern]';
|
|
20
|
+
description = 'Start a dev environment for a workspace or a specific component';
|
|
21
|
+
alias = 'c';
|
|
22
|
+
group = 'development';
|
|
23
|
+
shortDescription = '';
|
|
24
|
+
options = [
|
|
25
|
+
['d', 'dev', 'start UI server in dev mode.'],
|
|
26
|
+
['p', 'port [number]', 'port of the UI server.'],
|
|
27
|
+
['r', 'rebuild', 'rebuild the UI'],
|
|
28
|
+
['v', 'verbose', 'showing verbose output for inspection and prints stack trace'],
|
|
29
|
+
['', 'no-browser', 'do not automatically open browser when ready'],
|
|
30
|
+
['', 'skip-compilation', 'skip the auto-compilation before starting the web-server'],
|
|
31
|
+
] as CommandOptions;
|
|
32
|
+
|
|
33
|
+
constructor(
|
|
34
|
+
/**
|
|
35
|
+
* access to the extension instance.
|
|
36
|
+
*/
|
|
37
|
+
private ui: UiMain,
|
|
38
|
+
|
|
39
|
+
private logger: Logger
|
|
40
|
+
) {}
|
|
41
|
+
|
|
42
|
+
// async report([uiRootName, userPattern]: StartArgs, { dev, port, rebuild, verbose }: StartFlags): Promise<string> {
|
|
43
|
+
// this.logger.off();
|
|
44
|
+
// const pattern = userPattern && userPattern.toString();
|
|
45
|
+
|
|
46
|
+
// const uiServer = await this.ui.createRuntime({
|
|
47
|
+
// uiRootName,
|
|
48
|
+
// pattern,
|
|
49
|
+
// dev,
|
|
50
|
+
// port: port ? parseInt(port) : undefined,
|
|
51
|
+
// rebuild,
|
|
52
|
+
// verbose,
|
|
53
|
+
// });
|
|
54
|
+
|
|
55
|
+
// return `Bit server has started on port ${uiServer.port}`;
|
|
56
|
+
// }
|
|
57
|
+
|
|
58
|
+
async render(
|
|
59
|
+
[uiRootName, userPattern]: StartArgs,
|
|
60
|
+
{ dev, port, rebuild, verbose, noBrowser, skipCompilation }: StartFlags
|
|
61
|
+
): Promise<React.ReactElement> {
|
|
62
|
+
this.logger.off();
|
|
63
|
+
const appName = this.ui.getUiName(uiRootName);
|
|
64
|
+
await this.ui.invokePreStart({ skipCompilation });
|
|
65
|
+
const uiServer = this.ui.createRuntime({
|
|
66
|
+
uiRootName,
|
|
67
|
+
pattern: userPattern,
|
|
68
|
+
dev,
|
|
69
|
+
port: +port,
|
|
70
|
+
rebuild,
|
|
71
|
+
verbose,
|
|
72
|
+
});
|
|
73
|
+
|
|
74
|
+
if (!noBrowser) {
|
|
75
|
+
uiServer
|
|
76
|
+
.then(async (server) => {
|
|
77
|
+
if (!server.buildOptions?.launchBrowserOnStart) return undefined;
|
|
78
|
+
|
|
79
|
+
await server.whenReady;
|
|
80
|
+
|
|
81
|
+
return open(this.ui.publicUrl || server.fullUrl);
|
|
82
|
+
})
|
|
83
|
+
.catch((error) => this.logger.error(error));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// DO NOT CHANGE THIS - this meant to be an async hook.
|
|
87
|
+
// eslint-disable-next-line @typescript-eslint/no-floating-promises
|
|
88
|
+
this.ui.invokeOnStart();
|
|
89
|
+
this.ui.clearConsole();
|
|
90
|
+
|
|
91
|
+
return <UIServerConsole appName={appName} futureUiServer={uiServer} url={this.ui.publicUrl} />;
|
|
92
|
+
}
|
|
93
|
+
}
|
package/types/asset.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
declare module '*.png' {
|
|
2
|
+
const value: any;
|
|
3
|
+
export = value;
|
|
4
|
+
}
|
|
5
|
+
declare module '*.svg' {
|
|
6
|
+
import type { FunctionComponent, SVGProps } from 'react';
|
|
7
|
+
|
|
8
|
+
export const ReactComponent: FunctionComponent<SVGProps<SVGSVGElement> & { title?: string }>;
|
|
9
|
+
const src: string;
|
|
10
|
+
export default src;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// @TODO Gilad
|
|
14
|
+
declare module '*.jpg' {
|
|
15
|
+
const value: any;
|
|
16
|
+
export = value;
|
|
17
|
+
}
|
|
18
|
+
declare module '*.jpeg' {
|
|
19
|
+
const value: any;
|
|
20
|
+
export = value;
|
|
21
|
+
}
|
|
22
|
+
declare module '*.gif' {
|
|
23
|
+
const value: any;
|
|
24
|
+
export = value;
|
|
25
|
+
}
|
|
26
|
+
declare module '*.bmp' {
|
|
27
|
+
const value: any;
|
|
28
|
+
export = value;
|
|
29
|
+
}
|
package/types/style.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
declare module '*.module.css' {
|
|
2
|
+
const classes: { readonly [key: string]: string };
|
|
3
|
+
export default classes;
|
|
4
|
+
}
|
|
5
|
+
declare module '*.module.scss' {
|
|
6
|
+
const classes: { readonly [key: string]: string };
|
|
7
|
+
export default classes;
|
|
8
|
+
}
|
|
9
|
+
declare module '*.module.sass' {
|
|
10
|
+
const classes: { readonly [key: string]: string };
|
|
11
|
+
export default classes;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
declare module '*.module.less' {
|
|
15
|
+
const classes: { readonly [key: string]: string };
|
|
16
|
+
export default classes;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
declare module '*.less' {
|
|
20
|
+
const classes: { readonly [key: string]: string };
|
|
21
|
+
export default classes;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
declare module '*.css' {
|
|
25
|
+
const classes: { readonly [key: string]: string };
|
|
26
|
+
export default classes;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
declare module '*.sass' {
|
|
30
|
+
const classes: { readonly [key: string]: string };
|
|
31
|
+
export default classes;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
declare module '*.scss' {
|
|
35
|
+
const classes: { readonly [key: string]: string };
|
|
36
|
+
export default classes;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
declare module '*.mdx' {
|
|
40
|
+
const component: any;
|
|
41
|
+
export default component;
|
|
42
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import React, { ReactNode } from 'react';
|
|
2
|
+
import { Theme } from '@teambit/base-ui.theme.theme-provider';
|
|
3
|
+
import { IconFont } from '@teambit/design.theme.icons-font';
|
|
4
|
+
import { LoaderRibbon } from '@teambit/base-ui.loaders.loader-ribbon';
|
|
5
|
+
import { Roboto } from '@teambit/base-ui.theme.fonts.roboto';
|
|
6
|
+
import { TooltipMountPoint } from '@teambit/design.ui.tooltip';
|
|
7
|
+
|
|
8
|
+
import { LoaderContext, useLoaderApi } from '@teambit/ui-foundation.ui.global-loader';
|
|
9
|
+
import styles from './client-context.module.scss';
|
|
10
|
+
|
|
11
|
+
export function ClientContext({ children }: { children: ReactNode }) {
|
|
12
|
+
const [loaderApi, isLoading] = useLoaderApi();
|
|
13
|
+
|
|
14
|
+
return (
|
|
15
|
+
<React.StrictMode>
|
|
16
|
+
{/* TODO - try moving LoaderContext to contextSlot, and LoaderRibbon to hudSlot */}
|
|
17
|
+
<LoaderContext.Provider value={loaderApi}>
|
|
18
|
+
<IconFont query="q76y7n" />
|
|
19
|
+
<Theme>
|
|
20
|
+
<Roboto />
|
|
21
|
+
<LoaderRibbon active={isLoading} className={styles.loader} />
|
|
22
|
+
{children}
|
|
23
|
+
<TooltipMountPoint />
|
|
24
|
+
</Theme>
|
|
25
|
+
</LoaderContext.Provider>
|
|
26
|
+
</React.StrictMode>
|
|
27
|
+
);
|
|
28
|
+
}
|