@flightdev/script 0.0.2
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/LICENSE +21 -0
- package/README.md +154 -0
- package/dist/adapters/partytown.d.ts +155 -0
- package/dist/adapters/partytown.d.ts.map +1 -0
- package/dist/adapters/partytown.js +242 -0
- package/dist/adapters/partytown.js.map +1 -0
- package/dist/components/react.d.ts +98 -0
- package/dist/components/react.d.ts.map +1 -0
- package/dist/components/react.js +172 -0
- package/dist/components/react.js.map +1 -0
- package/dist/index.d.ts +100 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +240 -0
- package/dist/index.js.map +1 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024-2026 Flight Contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
# @flight-framework/script
|
|
2
|
+
|
|
3
|
+
Script loading optimization for improved Core Web Vitals.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @flight-framework/script
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Quick Start
|
|
12
|
+
|
|
13
|
+
```tsx
|
|
14
|
+
import { Script } from '@flight-framework/script/react';
|
|
15
|
+
|
|
16
|
+
function App() {
|
|
17
|
+
return (
|
|
18
|
+
<>
|
|
19
|
+
<Script
|
|
20
|
+
src="https://analytics.example.com/script.js"
|
|
21
|
+
strategy="afterInteractive"
|
|
22
|
+
/>
|
|
23
|
+
</>
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
## Loading Strategies
|
|
29
|
+
|
|
30
|
+
| Strategy | When Loaded | Use Case |
|
|
31
|
+
|----------|-------------|----------|
|
|
32
|
+
| `beforeInteractive` | Before hydration | Critical polyfills |
|
|
33
|
+
| `afterInteractive` | After page is interactive | Analytics, tracking |
|
|
34
|
+
| `lazyOnload` | On browser idle | Widgets, chat |
|
|
35
|
+
| `worker` | In web worker | Heavy processing |
|
|
36
|
+
|
|
37
|
+
## React Component
|
|
38
|
+
|
|
39
|
+
```tsx
|
|
40
|
+
import { Script } from '@flight-framework/script/react';
|
|
41
|
+
|
|
42
|
+
// External script
|
|
43
|
+
<Script src="https://example.com/script.js" strategy="afterInteractive" />
|
|
44
|
+
|
|
45
|
+
// Inline script
|
|
46
|
+
<Script id="config">
|
|
47
|
+
{`window.CONFIG = { api: 'https://api.example.com' };`}
|
|
48
|
+
</Script>
|
|
49
|
+
|
|
50
|
+
// With callbacks
|
|
51
|
+
<Script
|
|
52
|
+
src="https://sdk.example.com/v1.js"
|
|
53
|
+
onLoad={() => window.SDK.init()}
|
|
54
|
+
onError={(e) => console.error(e)}
|
|
55
|
+
/>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## useScript Hook
|
|
59
|
+
|
|
60
|
+
```tsx
|
|
61
|
+
import { useScript } from '@flight-framework/script/react';
|
|
62
|
+
|
|
63
|
+
function Widget() {
|
|
64
|
+
const { loading, loaded, error } = useScript(
|
|
65
|
+
'https://widget.example.com/sdk.js',
|
|
66
|
+
{ strategy: 'lazyOnload' }
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
if (loading) return <div>Loading...</div>;
|
|
70
|
+
if (error) return <div>Failed to load</div>;
|
|
71
|
+
if (loaded) return <div id="widget" />;
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
## Props
|
|
77
|
+
|
|
78
|
+
| Prop | Type | Default | Description |
|
|
79
|
+
|------|------|---------|-------------|
|
|
80
|
+
| `src` | `string` | - | Script URL |
|
|
81
|
+
| `strategy` | `string` | `'afterInteractive'` | Loading strategy |
|
|
82
|
+
| `onLoad` | `function` | - | Load callback |
|
|
83
|
+
| `onError` | `function` | - | Error callback |
|
|
84
|
+
| `id` | `string` | - | Script ID |
|
|
85
|
+
|
|
86
|
+
## Web Worker with Partytown
|
|
87
|
+
|
|
88
|
+
Move third-party scripts to a web worker for improved INP/FID:
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
npm install @builder.io/partytown
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
### Configuration
|
|
95
|
+
|
|
96
|
+
```typescript
|
|
97
|
+
import { partytown } from '@flight-framework/script/partytown';
|
|
98
|
+
|
|
99
|
+
const pt = partytown({
|
|
100
|
+
debug: process.env.NODE_ENV === 'development',
|
|
101
|
+
forward: ['dataLayer.push', 'gtag', 'fbq'],
|
|
102
|
+
autoDetect: true, // Auto-detect common analytics domains
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
// In your HTML head
|
|
106
|
+
// ${pt.headSnippet}
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
### Usage
|
|
110
|
+
|
|
111
|
+
```tsx
|
|
112
|
+
import { Script } from '@flight-framework/script/react';
|
|
113
|
+
|
|
114
|
+
// Runs in Web Worker via Partytown
|
|
115
|
+
<Script
|
|
116
|
+
src="https://www.googletagmanager.com/gtag/js?id=G-XXX"
|
|
117
|
+
strategy="worker"
|
|
118
|
+
/>
|
|
119
|
+
|
|
120
|
+
// Falls back gracefully if Partytown not installed
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### Pre-configured Domains
|
|
124
|
+
|
|
125
|
+
The `autoDetect` option automatically moves scripts from these domains to the worker:
|
|
126
|
+
|
|
127
|
+
- Google Analytics, Tag Manager, Ads
|
|
128
|
+
- Facebook Pixel, LinkedIn, Twitter
|
|
129
|
+
- Segment, Amplitude, Heap, Mixpanel
|
|
130
|
+
- Intercom, Hotjar, Mouseflow
|
|
131
|
+
- Sentry, LogRocket, Clarity
|
|
132
|
+
- And 15+ more
|
|
133
|
+
|
|
134
|
+
### Partytown API
|
|
135
|
+
|
|
136
|
+
```typescript
|
|
137
|
+
import {
|
|
138
|
+
partytown,
|
|
139
|
+
isPartytownReady,
|
|
140
|
+
loadWithPartytown,
|
|
141
|
+
} from '@flight-framework/script/partytown';
|
|
142
|
+
|
|
143
|
+
// Check if Partytown is available
|
|
144
|
+
if (isPartytownReady()) {
|
|
145
|
+
// Partytown is loaded
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// Load a script with Partytown (falls back if unavailable)
|
|
149
|
+
await loadWithPartytown('https://example.com/script.js');
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## License
|
|
153
|
+
|
|
154
|
+
MIT
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @flightdev/script - Partytown Adapter
|
|
3
|
+
*
|
|
4
|
+
* Move third-party scripts to a Web Worker for improved Core Web Vitals.
|
|
5
|
+
* This adapter integrates with @builder.io/partytown to offload scripts
|
|
6
|
+
* from the main thread.
|
|
7
|
+
*
|
|
8
|
+
* This is an OPTIONAL adapter. Install @builder.io/partytown only if you use it.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { partytown } from '@flightdev/script/partytown';
|
|
13
|
+
*
|
|
14
|
+
* // In your flight.config.ts or layout
|
|
15
|
+
* const config = partytown({
|
|
16
|
+
* debug: process.env.NODE_ENV === 'development',
|
|
17
|
+
* forward: ['dataLayer.push', 'gtag', 'fbq'],
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Partytown configuration options.
|
|
23
|
+
* These are passed directly to Partytown's configuration.
|
|
24
|
+
*/
|
|
25
|
+
export interface PartytownConfig {
|
|
26
|
+
/**
|
|
27
|
+
* Enable debug mode with console logging.
|
|
28
|
+
* @default false
|
|
29
|
+
*/
|
|
30
|
+
debug?: boolean;
|
|
31
|
+
/**
|
|
32
|
+
* Path to Partytown library files.
|
|
33
|
+
* @default '/~partytown/'
|
|
34
|
+
*/
|
|
35
|
+
lib?: string;
|
|
36
|
+
/**
|
|
37
|
+
* Functions to forward from worker to main thread.
|
|
38
|
+
* Common examples: 'dataLayer.push', 'gtag', 'fbq'
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* forward: [
|
|
43
|
+
* 'dataLayer.push',
|
|
44
|
+
* 'gtag',
|
|
45
|
+
* 'fbq',
|
|
46
|
+
* 'plausible',
|
|
47
|
+
* '_paq.push',
|
|
48
|
+
* ]
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
forward?: string[];
|
|
52
|
+
/**
|
|
53
|
+
* Domains that should be proxied through the main thread.
|
|
54
|
+
* Required for scripts that don't support CORS.
|
|
55
|
+
*/
|
|
56
|
+
proxyDomains?: string[];
|
|
57
|
+
/**
|
|
58
|
+
* Custom resolve function for script URLs.
|
|
59
|
+
* Use this to proxy third-party scripts through your server.
|
|
60
|
+
*/
|
|
61
|
+
resolveUrl?: (url: URL, location: URL, type: string) => URL | string | null;
|
|
62
|
+
/**
|
|
63
|
+
* Load scripts synchronously (blocking).
|
|
64
|
+
* Only use for critical scripts.
|
|
65
|
+
* @default false
|
|
66
|
+
*/
|
|
67
|
+
loadScriptsOnMainThread?: string[];
|
|
68
|
+
/**
|
|
69
|
+
* Sandbox iframe configuration.
|
|
70
|
+
*/
|
|
71
|
+
sandbox?: {
|
|
72
|
+
/** Allow scripts from these origins */
|
|
73
|
+
allowedOrigins?: string[];
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Partytown adapter options for Flight Framework.
|
|
78
|
+
*/
|
|
79
|
+
export interface PartytownAdapterOptions extends PartytownConfig {
|
|
80
|
+
/**
|
|
81
|
+
* Enable the Partytown adapter.
|
|
82
|
+
* @default true
|
|
83
|
+
*/
|
|
84
|
+
enabled?: boolean;
|
|
85
|
+
/**
|
|
86
|
+
* Auto-detect and transform analytics scripts.
|
|
87
|
+
* When true, common analytics scripts are automatically moved to worker.
|
|
88
|
+
* @default false
|
|
89
|
+
*/
|
|
90
|
+
autoDetect?: boolean;
|
|
91
|
+
/**
|
|
92
|
+
* Known third-party domains to always run in worker.
|
|
93
|
+
*/
|
|
94
|
+
knownDomains?: string[];
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Result of Partytown adapter initialization.
|
|
98
|
+
*/
|
|
99
|
+
export interface PartytownAdapterResult {
|
|
100
|
+
/** Whether Partytown is enabled */
|
|
101
|
+
enabled: boolean;
|
|
102
|
+
/** Configuration to pass to Partytown snippet */
|
|
103
|
+
config: PartytownConfig;
|
|
104
|
+
/** HTML snippet to inject in <head> */
|
|
105
|
+
headSnippet: string;
|
|
106
|
+
/** Check if a script should run in worker */
|
|
107
|
+
shouldRunInWorker: (src: string) => boolean;
|
|
108
|
+
/** Transform a script tag for Partytown */
|
|
109
|
+
transformScript: (src: string) => {
|
|
110
|
+
type: string;
|
|
111
|
+
src: string;
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Create a Partytown adapter for Flight Framework.
|
|
116
|
+
*
|
|
117
|
+
* @param options - Partytown configuration options
|
|
118
|
+
* @returns Partytown adapter result with configuration and helpers
|
|
119
|
+
*
|
|
120
|
+
* @example
|
|
121
|
+
* ```typescript
|
|
122
|
+
* // Basic usage
|
|
123
|
+
* const pt = partytown({
|
|
124
|
+
* forward: ['dataLayer.push', 'gtag'],
|
|
125
|
+
* });
|
|
126
|
+
*
|
|
127
|
+
* // In your HTML head
|
|
128
|
+
* ${pt.headSnippet}
|
|
129
|
+
*
|
|
130
|
+
* // Transform scripts
|
|
131
|
+
* if (pt.shouldRunInWorker(scriptSrc)) {
|
|
132
|
+
* const { type, src } = pt.transformScript(scriptSrc);
|
|
133
|
+
* // Render: <script type="text/partytown" src={src} />
|
|
134
|
+
* }
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
export declare function partytown(options?: PartytownAdapterOptions): PartytownAdapterResult;
|
|
138
|
+
/**
|
|
139
|
+
* Generate inline Partytown snippet (for when async loading isn't possible).
|
|
140
|
+
* This should be used with the actual Partytown snippet content.
|
|
141
|
+
*/
|
|
142
|
+
export declare function generateInlineSnippet(config: PartytownConfig): string;
|
|
143
|
+
/**
|
|
144
|
+
* Check if Partytown is available and initialized.
|
|
145
|
+
*/
|
|
146
|
+
export declare function isPartytownReady(): boolean;
|
|
147
|
+
/**
|
|
148
|
+
* Dynamically load a script with Partytown.
|
|
149
|
+
* Falls back to normal loading if Partytown isn't available.
|
|
150
|
+
*/
|
|
151
|
+
export declare function loadWithPartytown(src: string, options?: {
|
|
152
|
+
fallback?: boolean;
|
|
153
|
+
}): Promise<void>;
|
|
154
|
+
export default partytown;
|
|
155
|
+
//# sourceMappingURL=partytown.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"partytown.d.ts","sourceRoot":"","sources":["../../src/adapters/partytown.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAMH;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC5B;;;OAGG;IACH,KAAK,CAAC,EAAE,OAAO,CAAC;IAEhB;;;OAGG;IACH,GAAG,CAAC,EAAE,MAAM,CAAC;IAEb;;;;;;;;;;;;;;OAcG;IACH,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IAExB;;;OAGG;IACH,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,QAAQ,EAAE,GAAG,EAAE,IAAI,EAAE,MAAM,KAAK,GAAG,GAAG,MAAM,GAAG,IAAI,CAAC;IAE5E;;;;OAIG;IACH,uBAAuB,CAAC,EAAE,MAAM,EAAE,CAAC;IAEnC;;OAEG;IACH,OAAO,CAAC,EAAE;QACN,uCAAuC;QACvC,cAAc,CAAC,EAAE,MAAM,EAAE,CAAC;KAC7B,CAAC;CACL;AAED;;GAEG;AACH,MAAM,WAAW,uBAAwB,SAAQ,eAAe;IAC5D;;;OAGG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAElB;;;;OAIG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IAErB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,sBAAsB;IACnC,mCAAmC;IACnC,OAAO,EAAE,OAAO,CAAC;IACjB,iDAAiD;IACjD,MAAM,EAAE,eAAe,CAAC;IACxB,uCAAuC;IACvC,WAAW,EAAE,MAAM,CAAC;IACpB,6CAA6C;IAC7C,iBAAiB,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IAC5C,2CAA2C;IAC3C,eAAe,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC;CACnE;AA8CD;;;;;;;;;;;;;;;;;;;;;;GAsBG;AACH,wBAAgB,SAAS,CAAC,OAAO,GAAE,uBAA4B,GAAG,sBAAsB,CAmFvF;AA2CD;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,eAAe,GAAG,MAAM,CAWrE;AAMD;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAG1C;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC7B,GAAG,EAAE,MAAM,EACX,OAAO,GAAE;IAAE,QAAQ,CAAC,EAAE,OAAO,CAAA;CAAO,GACrC,OAAO,CAAC,IAAI,CAAC,CA0Bf;AAMD,eAAe,SAAS,CAAC"}
|
|
@@ -0,0 +1,242 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @flightdev/script - Partytown Adapter
|
|
3
|
+
*
|
|
4
|
+
* Move third-party scripts to a Web Worker for improved Core Web Vitals.
|
|
5
|
+
* This adapter integrates with @builder.io/partytown to offload scripts
|
|
6
|
+
* from the main thread.
|
|
7
|
+
*
|
|
8
|
+
* This is an OPTIONAL adapter. Install @builder.io/partytown only if you use it.
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* import { partytown } from '@flightdev/script/partytown';
|
|
13
|
+
*
|
|
14
|
+
* // In your flight.config.ts or layout
|
|
15
|
+
* const config = partytown({
|
|
16
|
+
* debug: process.env.NODE_ENV === 'development',
|
|
17
|
+
* forward: ['dataLayer.push', 'gtag', 'fbq'],
|
|
18
|
+
* });
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
// ============================================================================
|
|
22
|
+
// Known Third-Party Domains
|
|
23
|
+
// ============================================================================
|
|
24
|
+
/**
|
|
25
|
+
* Pre-configured domains known to work with Partytown.
|
|
26
|
+
* These scripts are safe to move to a web worker.
|
|
27
|
+
*/
|
|
28
|
+
const DEFAULT_KNOWN_DOMAINS = [
|
|
29
|
+
'google-analytics.com',
|
|
30
|
+
'googletagmanager.com',
|
|
31
|
+
'connect.facebook.net',
|
|
32
|
+
'www.googleadservices.com',
|
|
33
|
+
'googleads.g.doubleclick.net',
|
|
34
|
+
'snap.licdn.com',
|
|
35
|
+
'static.ads-twitter.com',
|
|
36
|
+
'analytics.tiktok.com',
|
|
37
|
+
'plausible.io',
|
|
38
|
+
'cdn.segment.com',
|
|
39
|
+
'js.hs-scripts.com',
|
|
40
|
+
'js.hs-analytics.net',
|
|
41
|
+
'cdn.amplitude.com',
|
|
42
|
+
'cdn.heapanalytics.com',
|
|
43
|
+
'cdn.mxpnl.com',
|
|
44
|
+
'js.intercomcdn.com',
|
|
45
|
+
'widget.intercom.io',
|
|
46
|
+
'static.hotjar.com',
|
|
47
|
+
'cdn.mouseflow.com',
|
|
48
|
+
'cdn.logrocket.io',
|
|
49
|
+
'js.sentry-cdn.com',
|
|
50
|
+
'browser.sentry-cdn.com',
|
|
51
|
+
'cdn.clarity.ms',
|
|
52
|
+
'static.klaviyo.com',
|
|
53
|
+
'js.driftt.com',
|
|
54
|
+
'widget.crisp.chat',
|
|
55
|
+
'embed.typeform.com',
|
|
56
|
+
'player.vimeo.com',
|
|
57
|
+
'www.youtube.com',
|
|
58
|
+
];
|
|
59
|
+
// ============================================================================
|
|
60
|
+
// Partytown Adapter
|
|
61
|
+
// ============================================================================
|
|
62
|
+
/**
|
|
63
|
+
* Create a Partytown adapter for Flight Framework.
|
|
64
|
+
*
|
|
65
|
+
* @param options - Partytown configuration options
|
|
66
|
+
* @returns Partytown adapter result with configuration and helpers
|
|
67
|
+
*
|
|
68
|
+
* @example
|
|
69
|
+
* ```typescript
|
|
70
|
+
* // Basic usage
|
|
71
|
+
* const pt = partytown({
|
|
72
|
+
* forward: ['dataLayer.push', 'gtag'],
|
|
73
|
+
* });
|
|
74
|
+
*
|
|
75
|
+
* // In your HTML head
|
|
76
|
+
* ${pt.headSnippet}
|
|
77
|
+
*
|
|
78
|
+
* // Transform scripts
|
|
79
|
+
* if (pt.shouldRunInWorker(scriptSrc)) {
|
|
80
|
+
* const { type, src } = pt.transformScript(scriptSrc);
|
|
81
|
+
* // Render: <script type="text/partytown" src={src} />
|
|
82
|
+
* }
|
|
83
|
+
* ```
|
|
84
|
+
*/
|
|
85
|
+
export function partytown(options = {}) {
|
|
86
|
+
const { enabled = true, debug = false, lib = '/~partytown/', forward = [], proxyDomains = [], autoDetect = false, knownDomains = [], loadScriptsOnMainThread = [], resolveUrl, sandbox, } = options;
|
|
87
|
+
// Merge known domains with user-provided domains
|
|
88
|
+
const allKnownDomains = autoDetect
|
|
89
|
+
? [...DEFAULT_KNOWN_DOMAINS, ...knownDomains]
|
|
90
|
+
: knownDomains;
|
|
91
|
+
// Build Partytown configuration object
|
|
92
|
+
const config = {
|
|
93
|
+
debug,
|
|
94
|
+
lib,
|
|
95
|
+
forward,
|
|
96
|
+
loadScriptsOnMainThread,
|
|
97
|
+
};
|
|
98
|
+
if (resolveUrl) {
|
|
99
|
+
config.resolveUrl = resolveUrl;
|
|
100
|
+
}
|
|
101
|
+
if (sandbox) {
|
|
102
|
+
config.sandbox = sandbox;
|
|
103
|
+
}
|
|
104
|
+
// Generate head snippet for SSR
|
|
105
|
+
const headSnippet = generateHeadSnippet(config, proxyDomains);
|
|
106
|
+
// Helper to check if script should run in worker
|
|
107
|
+
const shouldRunInWorker = (src) => {
|
|
108
|
+
if (!enabled)
|
|
109
|
+
return false;
|
|
110
|
+
if (!src)
|
|
111
|
+
return false;
|
|
112
|
+
try {
|
|
113
|
+
const url = new URL(src, 'https://example.com');
|
|
114
|
+
const hostname = url.hostname.toLowerCase();
|
|
115
|
+
// Check against known domains
|
|
116
|
+
for (const domain of allKnownDomains) {
|
|
117
|
+
if (hostname.includes(domain)) {
|
|
118
|
+
return true;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// Check against proxy domains
|
|
122
|
+
for (const domain of proxyDomains) {
|
|
123
|
+
if (hostname.includes(domain)) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// Invalid URL, don't transform
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
return false;
|
|
133
|
+
};
|
|
134
|
+
// Helper to transform script tag attributes
|
|
135
|
+
const transformScript = (src) => {
|
|
136
|
+
return {
|
|
137
|
+
type: 'text/partytown',
|
|
138
|
+
src,
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
return {
|
|
142
|
+
enabled,
|
|
143
|
+
config,
|
|
144
|
+
headSnippet,
|
|
145
|
+
shouldRunInWorker,
|
|
146
|
+
transformScript,
|
|
147
|
+
};
|
|
148
|
+
}
|
|
149
|
+
// ============================================================================
|
|
150
|
+
// Helper Functions
|
|
151
|
+
// ============================================================================
|
|
152
|
+
/**
|
|
153
|
+
* Generate the Partytown head snippet for SSR.
|
|
154
|
+
*/
|
|
155
|
+
function generateHeadSnippet(config, proxyDomains) {
|
|
156
|
+
const configJson = JSON.stringify({
|
|
157
|
+
debug: config.debug,
|
|
158
|
+
lib: config.lib,
|
|
159
|
+
forward: config.forward,
|
|
160
|
+
});
|
|
161
|
+
// Generate resolve URL function if proxy domains are specified
|
|
162
|
+
let resolveUrlScript = '';
|
|
163
|
+
if (proxyDomains.length > 0) {
|
|
164
|
+
const domainChecks = proxyDomains
|
|
165
|
+
.map(d => `url.hostname.includes('${d}')`)
|
|
166
|
+
.join(' || ');
|
|
167
|
+
resolveUrlScript = `
|
|
168
|
+
resolveUrl: function(url, location, type) {
|
|
169
|
+
if (${domainChecks}) {
|
|
170
|
+
var proxyUrl = new URL('/_flight/proxy');
|
|
171
|
+
proxyUrl.searchParams.set('url', url.href);
|
|
172
|
+
return proxyUrl;
|
|
173
|
+
}
|
|
174
|
+
return url;
|
|
175
|
+
},`;
|
|
176
|
+
}
|
|
177
|
+
return `
|
|
178
|
+
<!-- Partytown Configuration (Flight Framework) -->
|
|
179
|
+
<script>
|
|
180
|
+
partytown = ${configJson.slice(0, -1)}${resolveUrlScript}};
|
|
181
|
+
</script>
|
|
182
|
+
<script src="${config.lib}partytown.js" async></script>
|
|
183
|
+
`.trim();
|
|
184
|
+
}
|
|
185
|
+
/**
|
|
186
|
+
* Generate inline Partytown snippet (for when async loading isn't possible).
|
|
187
|
+
* This should be used with the actual Partytown snippet content.
|
|
188
|
+
*/
|
|
189
|
+
export function generateInlineSnippet(config) {
|
|
190
|
+
return `
|
|
191
|
+
<script>
|
|
192
|
+
/* Partytown Config */
|
|
193
|
+
partytown = {
|
|
194
|
+
debug: ${config.debug || false},
|
|
195
|
+
lib: '${config.lib || '/~partytown/'}',
|
|
196
|
+
forward: ${JSON.stringify(config.forward || [])}
|
|
197
|
+
};
|
|
198
|
+
</script>
|
|
199
|
+
`.trim();
|
|
200
|
+
}
|
|
201
|
+
// ============================================================================
|
|
202
|
+
// React Hook (for client-side initialization)
|
|
203
|
+
// ============================================================================
|
|
204
|
+
/**
|
|
205
|
+
* Check if Partytown is available and initialized.
|
|
206
|
+
*/
|
|
207
|
+
export function isPartytownReady() {
|
|
208
|
+
if (typeof window === 'undefined')
|
|
209
|
+
return false;
|
|
210
|
+
return typeof window.partytown !== 'undefined';
|
|
211
|
+
}
|
|
212
|
+
/**
|
|
213
|
+
* Dynamically load a script with Partytown.
|
|
214
|
+
* Falls back to normal loading if Partytown isn't available.
|
|
215
|
+
*/
|
|
216
|
+
export function loadWithPartytown(src, options = {}) {
|
|
217
|
+
const { fallback = true } = options;
|
|
218
|
+
return new Promise((resolve, reject) => {
|
|
219
|
+
if (typeof document === 'undefined') {
|
|
220
|
+
resolve();
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
const script = document.createElement('script');
|
|
224
|
+
if (isPartytownReady()) {
|
|
225
|
+
script.type = 'text/partytown';
|
|
226
|
+
}
|
|
227
|
+
else if (!fallback) {
|
|
228
|
+
reject(new Error('Partytown not available and fallback disabled'));
|
|
229
|
+
return;
|
|
230
|
+
}
|
|
231
|
+
script.src = src;
|
|
232
|
+
script.async = true;
|
|
233
|
+
script.onload = () => resolve();
|
|
234
|
+
script.onerror = () => reject(new Error(`Failed to load: ${src}`));
|
|
235
|
+
document.head.appendChild(script);
|
|
236
|
+
});
|
|
237
|
+
}
|
|
238
|
+
// ============================================================================
|
|
239
|
+
// Exports
|
|
240
|
+
// ============================================================================
|
|
241
|
+
export default partytown;
|
|
242
|
+
//# sourceMappingURL=partytown.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"partytown.js","sourceRoot":"","sources":["../../src/adapters/partytown.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @flightdev/script/react - React Script Component
|
|
3
|
+
*
|
|
4
|
+
* React component for optimized script loading.
|
|
5
|
+
*/
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import { type ScriptOptions, type ScriptState } from '../index.js';
|
|
8
|
+
export interface ScriptProps extends ScriptOptions {
|
|
9
|
+
/** Script source URL (required unless using dangerouslySetInnerHTML) */
|
|
10
|
+
src?: string;
|
|
11
|
+
/** Children for inline scripts */
|
|
12
|
+
children?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Optimized script loading component
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```tsx
|
|
19
|
+
* import { Script } from '@flightdev/script/react';
|
|
20
|
+
*
|
|
21
|
+
* // External script with afterInteractive strategy (default)
|
|
22
|
+
* <Script src="https://analytics.example.com/script.js" />
|
|
23
|
+
*
|
|
24
|
+
* // Lazy load for non-critical scripts
|
|
25
|
+
* <Script
|
|
26
|
+
* src="https://widget.example.com/embed.js"
|
|
27
|
+
* strategy="lazyOnload"
|
|
28
|
+
* onLoad={() => console.log('Widget loaded!')}
|
|
29
|
+
* />
|
|
30
|
+
*
|
|
31
|
+
* // Inline script
|
|
32
|
+
* <Script id="my-inline-script">
|
|
33
|
+
* {`console.log('Hello from inline script!')`}
|
|
34
|
+
* </Script>
|
|
35
|
+
*
|
|
36
|
+
* // Critical script (blocks hydration)
|
|
37
|
+
* <Script
|
|
38
|
+
* src="/critical.js"
|
|
39
|
+
* strategy="beforeInteractive"
|
|
40
|
+
* />
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare function Script({ src, children, dangerouslySetInnerHTML, strategy, onLoad, onError, onReady, id, async: asyncAttr, defer, type, nonce, ...rest }: ScriptProps): React.ReactElement | null;
|
|
44
|
+
/**
|
|
45
|
+
* Hook to load and track script state
|
|
46
|
+
*
|
|
47
|
+
* @example
|
|
48
|
+
* ```tsx
|
|
49
|
+
* import { useScript } from '@flightdev/script/react';
|
|
50
|
+
*
|
|
51
|
+
* function WidgetComponent() {
|
|
52
|
+
* const { loaded, loading, error } = useScript(
|
|
53
|
+
* 'https://widget.example.com/sdk.js',
|
|
54
|
+
* { strategy: 'lazyOnload' }
|
|
55
|
+
* );
|
|
56
|
+
*
|
|
57
|
+
* if (loading) return <div>Loading widget...</div>;
|
|
58
|
+
* if (error) return <div>Failed to load widget</div>;
|
|
59
|
+
* if (loaded) return <div id="widget-container" />;
|
|
60
|
+
* return null;
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export declare function useScript(src: string, options?: Omit<ScriptOptions, 'src' | 'dangerouslySetInnerHTML'>): ScriptState;
|
|
65
|
+
export interface ScriptProviderProps {
|
|
66
|
+
/** Scripts to preload/preconnect */
|
|
67
|
+
scripts?: Array<{
|
|
68
|
+
src: string;
|
|
69
|
+
preconnect?: boolean;
|
|
70
|
+
preload?: boolean;
|
|
71
|
+
}>;
|
|
72
|
+
children: React.ReactNode;
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Provider for script preloading hints
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```tsx
|
|
79
|
+
* import { ScriptProvider } from '@flightdev/script/react';
|
|
80
|
+
*
|
|
81
|
+
* function App() {
|
|
82
|
+
* return (
|
|
83
|
+
* <ScriptProvider
|
|
84
|
+
* scripts={[
|
|
85
|
+
* { src: 'https://analytics.example.com', preconnect: true },
|
|
86
|
+
* { src: 'https://cdn.example.com/sdk.js', preload: true },
|
|
87
|
+
* ]}
|
|
88
|
+
* >
|
|
89
|
+
* <MyApp />
|
|
90
|
+
* </ScriptProvider>
|
|
91
|
+
* );
|
|
92
|
+
* }
|
|
93
|
+
* ```
|
|
94
|
+
*/
|
|
95
|
+
export declare function ScriptProvider({ scripts, children }: ScriptProviderProps): React.ReactElement;
|
|
96
|
+
export { loadScript, preconnect, dnsPrefetch, preloadScript, isScriptLoaded, waitForScript } from '../index.js';
|
|
97
|
+
export type { ScriptOptions, ScriptStrategy, ScriptState } from '../index.js';
|
|
98
|
+
//# sourceMappingURL=react.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.d.ts","sourceRoot":"","sources":["../../src/components/react.tsx"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAA2C,MAAM,OAAO,CAAC;AAChE,OAAO,EAEH,KAAK,aAAa,EAElB,KAAK,WAAW,EACnB,MAAM,aAAa,CAAC;AAMrB,MAAM,WAAW,WAAY,SAAQ,aAAa;IAC9C,wEAAwE;IACxE,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,MAAM,CAAC,EACnB,GAAG,EACH,QAAQ,EACR,uBAAuB,EACvB,QAA6B,EAC7B,MAAM,EACN,OAAO,EACP,OAAO,EACP,EAAE,EACF,KAAK,EAAE,SAAS,EAChB,KAAK,EACL,IAAI,EACJ,KAAK,EACL,GAAG,IAAI,EACV,EAAE,WAAW,GAAG,KAAK,CAAC,YAAY,GAAG,IAAI,CAsEzC;AAMD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAgB,SAAS,CACrB,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,yBAAyB,CAAM,GACrE,WAAW,CA8Bb;AAMD,MAAM,WAAW,mBAAmB;IAChC,oCAAoC;IACpC,OAAO,CAAC,EAAE,KAAK,CAAC;QACZ,GAAG,EAAE,MAAM,CAAC;QACZ,UAAU,CAAC,EAAE,OAAO,CAAC;QACrB,OAAO,CAAC,EAAE,OAAO,CAAC;KACrB,CAAC,CAAC;IACH,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC7B;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,cAAc,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,mBAAmB,GAAG,KAAK,CAAC,YAAY,CAwB7F;AAMD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAChH,YAAY,EAAE,aAAa,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
|
+
/**
|
|
3
|
+
* @flightdev/script/react - React Script Component
|
|
4
|
+
*
|
|
5
|
+
* React component for optimized script loading.
|
|
6
|
+
*/
|
|
7
|
+
import React, { useEffect, useState } from 'react';
|
|
8
|
+
import { loadScript } from '../index.js';
|
|
9
|
+
/**
|
|
10
|
+
* Optimized script loading component
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```tsx
|
|
14
|
+
* import { Script } from '@flightdev/script/react';
|
|
15
|
+
*
|
|
16
|
+
* // External script with afterInteractive strategy (default)
|
|
17
|
+
* <Script src="https://analytics.example.com/script.js" />
|
|
18
|
+
*
|
|
19
|
+
* // Lazy load for non-critical scripts
|
|
20
|
+
* <Script
|
|
21
|
+
* src="https://widget.example.com/embed.js"
|
|
22
|
+
* strategy="lazyOnload"
|
|
23
|
+
* onLoad={() => console.log('Widget loaded!')}
|
|
24
|
+
* />
|
|
25
|
+
*
|
|
26
|
+
* // Inline script
|
|
27
|
+
* <Script id="my-inline-script">
|
|
28
|
+
* {`console.log('Hello from inline script!')`}
|
|
29
|
+
* </Script>
|
|
30
|
+
*
|
|
31
|
+
* // Critical script (blocks hydration)
|
|
32
|
+
* <Script
|
|
33
|
+
* src="/critical.js"
|
|
34
|
+
* strategy="beforeInteractive"
|
|
35
|
+
* />
|
|
36
|
+
* ```
|
|
37
|
+
*/
|
|
38
|
+
export function Script({ src, children, dangerouslySetInnerHTML, strategy = 'afterInteractive', onLoad, onError, onReady, id, async: asyncAttr, defer, type, nonce, ...rest }) {
|
|
39
|
+
const [loaded, setLoaded] = useState(false);
|
|
40
|
+
useEffect(() => {
|
|
41
|
+
// Handle inline scripts
|
|
42
|
+
if (!src && (children || dangerouslySetInnerHTML)) {
|
|
43
|
+
const script = document.createElement('script');
|
|
44
|
+
if (id)
|
|
45
|
+
script.id = id;
|
|
46
|
+
if (type)
|
|
47
|
+
script.type = type;
|
|
48
|
+
if (nonce)
|
|
49
|
+
script.nonce = nonce;
|
|
50
|
+
// Add data attributes
|
|
51
|
+
Object.entries(rest).forEach(([key, value]) => {
|
|
52
|
+
if (key.startsWith('data-') && value) {
|
|
53
|
+
script.setAttribute(key, value);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
script.textContent = children || dangerouslySetInnerHTML?.__html || '';
|
|
57
|
+
document.body.appendChild(script);
|
|
58
|
+
setLoaded(true);
|
|
59
|
+
onLoad?.();
|
|
60
|
+
onReady?.();
|
|
61
|
+
return () => {
|
|
62
|
+
script.remove();
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
// Handle external scripts
|
|
66
|
+
if (src) {
|
|
67
|
+
onReady?.();
|
|
68
|
+
loadScript(src, {
|
|
69
|
+
strategy,
|
|
70
|
+
onLoad: () => {
|
|
71
|
+
setLoaded(true);
|
|
72
|
+
onLoad?.();
|
|
73
|
+
},
|
|
74
|
+
onError,
|
|
75
|
+
id,
|
|
76
|
+
async: asyncAttr,
|
|
77
|
+
defer,
|
|
78
|
+
type,
|
|
79
|
+
nonce,
|
|
80
|
+
...rest,
|
|
81
|
+
}).catch((error) => {
|
|
82
|
+
onError?.(error instanceof Error ? error : new Error(String(error)));
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}, [src, strategy, id]);
|
|
86
|
+
// For SSR/beforeInteractive, render the script tag directly
|
|
87
|
+
if (strategy === 'beforeInteractive' && src) {
|
|
88
|
+
return (_jsx("script", { src: src, id: id, async: asyncAttr, defer: defer, type: type, nonce: nonce, ...rest }));
|
|
89
|
+
}
|
|
90
|
+
// For other strategies, we load via useEffect (no SSR output)
|
|
91
|
+
return null;
|
|
92
|
+
}
|
|
93
|
+
// ============================================================================
|
|
94
|
+
// useScript Hook
|
|
95
|
+
// ============================================================================
|
|
96
|
+
/**
|
|
97
|
+
* Hook to load and track script state
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```tsx
|
|
101
|
+
* import { useScript } from '@flightdev/script/react';
|
|
102
|
+
*
|
|
103
|
+
* function WidgetComponent() {
|
|
104
|
+
* const { loaded, loading, error } = useScript(
|
|
105
|
+
* 'https://widget.example.com/sdk.js',
|
|
106
|
+
* { strategy: 'lazyOnload' }
|
|
107
|
+
* );
|
|
108
|
+
*
|
|
109
|
+
* if (loading) return <div>Loading widget...</div>;
|
|
110
|
+
* if (error) return <div>Failed to load widget</div>;
|
|
111
|
+
* if (loaded) return <div id="widget-container" />;
|
|
112
|
+
* return null;
|
|
113
|
+
* }
|
|
114
|
+
* ```
|
|
115
|
+
*/
|
|
116
|
+
export function useScript(src, options = {}) {
|
|
117
|
+
const [state, setState] = useState({
|
|
118
|
+
loading: true,
|
|
119
|
+
loaded: false,
|
|
120
|
+
error: null,
|
|
121
|
+
});
|
|
122
|
+
useEffect(() => {
|
|
123
|
+
setState({ loading: true, loaded: false, error: null });
|
|
124
|
+
loadScript(src, {
|
|
125
|
+
...options,
|
|
126
|
+
onLoad: () => {
|
|
127
|
+
setState({ loading: false, loaded: true, error: null });
|
|
128
|
+
options.onLoad?.();
|
|
129
|
+
},
|
|
130
|
+
onError: (error) => {
|
|
131
|
+
setState({ loading: false, loaded: false, error });
|
|
132
|
+
options.onError?.(error);
|
|
133
|
+
},
|
|
134
|
+
}).catch((error) => {
|
|
135
|
+
setState({
|
|
136
|
+
loading: false,
|
|
137
|
+
loaded: false,
|
|
138
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
139
|
+
});
|
|
140
|
+
});
|
|
141
|
+
}, [src, options.strategy]);
|
|
142
|
+
return state;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Provider for script preloading hints
|
|
146
|
+
*
|
|
147
|
+
* @example
|
|
148
|
+
* ```tsx
|
|
149
|
+
* import { ScriptProvider } from '@flightdev/script/react';
|
|
150
|
+
*
|
|
151
|
+
* function App() {
|
|
152
|
+
* return (
|
|
153
|
+
* <ScriptProvider
|
|
154
|
+
* scripts={[
|
|
155
|
+
* { src: 'https://analytics.example.com', preconnect: true },
|
|
156
|
+
* { src: 'https://cdn.example.com/sdk.js', preload: true },
|
|
157
|
+
* ]}
|
|
158
|
+
* >
|
|
159
|
+
* <MyApp />
|
|
160
|
+
* </ScriptProvider>
|
|
161
|
+
* );
|
|
162
|
+
* }
|
|
163
|
+
* ```
|
|
164
|
+
*/
|
|
165
|
+
export function ScriptProvider({ scripts, children }) {
|
|
166
|
+
return (_jsxs(_Fragment, { children: [scripts?.map((script, i) => (_jsxs(React.Fragment, { children: [script.preconnect && (_jsx("link", { rel: "preconnect", href: new URL(script.src).origin, crossOrigin: "anonymous" })), script.preload && (_jsx("link", { rel: "preload", href: script.src, as: "script" }))] }, i))), children] }));
|
|
167
|
+
}
|
|
168
|
+
// ============================================================================
|
|
169
|
+
// Re-exports
|
|
170
|
+
// ============================================================================
|
|
171
|
+
export { loadScript, preconnect, dnsPrefetch, preloadScript, isScriptLoaded, waitForScript } from '../index.js';
|
|
172
|
+
//# sourceMappingURL=react.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"react.js","sourceRoot":"","sources":["../../src/components/react.tsx"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @flightdev/script - Agnostic Script Loading Optimization
|
|
3
|
+
*
|
|
4
|
+
* Control how third-party scripts load to improve Core Web Vitals.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { Script } from '@flightdev/script/react';
|
|
9
|
+
*
|
|
10
|
+
* // Load analytics after page is interactive
|
|
11
|
+
* <Script
|
|
12
|
+
* src="https://analytics.example.com/script.js"
|
|
13
|
+
* strategy="afterInteractive"
|
|
14
|
+
* />
|
|
15
|
+
*
|
|
16
|
+
* // Lazy load when visible
|
|
17
|
+
* <Script
|
|
18
|
+
* src="https://widget.example.com/embed.js"
|
|
19
|
+
* strategy="lazyOnload"
|
|
20
|
+
* />
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
/**
|
|
24
|
+
* Script loading strategy
|
|
25
|
+
*
|
|
26
|
+
* - `beforeInteractive`: Load immediately, blocks hydration (use sparingly)
|
|
27
|
+
* - `afterInteractive`: Load after page is interactive (default)
|
|
28
|
+
* - `lazyOnload`: Load when browser is idle or on scroll
|
|
29
|
+
* - `worker`: Load in a web worker (experimental)
|
|
30
|
+
*/
|
|
31
|
+
export type ScriptStrategy = 'beforeInteractive' | 'afterInteractive' | 'lazyOnload' | 'worker';
|
|
32
|
+
/**
|
|
33
|
+
* Script loading options
|
|
34
|
+
*/
|
|
35
|
+
export interface ScriptOptions {
|
|
36
|
+
/** Script source URL */
|
|
37
|
+
src?: string;
|
|
38
|
+
/** Inline script content */
|
|
39
|
+
dangerouslySetInnerHTML?: {
|
|
40
|
+
__html: string;
|
|
41
|
+
};
|
|
42
|
+
/** Loading strategy */
|
|
43
|
+
strategy?: ScriptStrategy;
|
|
44
|
+
/** Called when script loads */
|
|
45
|
+
onLoad?: () => void;
|
|
46
|
+
/** Called on script error */
|
|
47
|
+
onError?: (error: Error) => void;
|
|
48
|
+
/** Called before script loads */
|
|
49
|
+
onReady?: () => void;
|
|
50
|
+
/** Script ID for deduplication */
|
|
51
|
+
id?: string;
|
|
52
|
+
/** Async attribute */
|
|
53
|
+
async?: boolean;
|
|
54
|
+
/** Defer attribute */
|
|
55
|
+
defer?: boolean;
|
|
56
|
+
/** Module script */
|
|
57
|
+
type?: 'module' | 'text/javascript';
|
|
58
|
+
/** Nonce for CSP */
|
|
59
|
+
nonce?: string;
|
|
60
|
+
/** data-* attributes */
|
|
61
|
+
[key: `data-${string}`]: string | undefined;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Script state
|
|
65
|
+
*/
|
|
66
|
+
export interface ScriptState {
|
|
67
|
+
loading: boolean;
|
|
68
|
+
loaded: boolean;
|
|
69
|
+
error: Error | null;
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Load a script programmatically
|
|
73
|
+
*/
|
|
74
|
+
export declare function loadScript(src: string, options?: Omit<ScriptOptions, 'src' | 'dangerouslySetInnerHTML'>): Promise<void>;
|
|
75
|
+
/**
|
|
76
|
+
* Preconnect to a domain for faster script loading
|
|
77
|
+
*/
|
|
78
|
+
export declare function preconnect(url: string, options?: {
|
|
79
|
+
crossOrigin?: boolean;
|
|
80
|
+
}): void;
|
|
81
|
+
/**
|
|
82
|
+
* DNS prefetch for a domain
|
|
83
|
+
*/
|
|
84
|
+
export declare function dnsPrefetch(url: string): void;
|
|
85
|
+
/**
|
|
86
|
+
* Preload a script without executing
|
|
87
|
+
*/
|
|
88
|
+
export declare function preloadScript(src: string, options?: {
|
|
89
|
+
as?: 'script';
|
|
90
|
+
}): void;
|
|
91
|
+
/**
|
|
92
|
+
* Check if a script is already loaded
|
|
93
|
+
*/
|
|
94
|
+
export declare function isScriptLoaded(src: string): boolean;
|
|
95
|
+
/**
|
|
96
|
+
* Wait for a script to load
|
|
97
|
+
*/
|
|
98
|
+
export declare function waitForScript(src: string): Promise<void>;
|
|
99
|
+
export type { ScriptOptions as Options, ScriptStrategy as Strategy };
|
|
100
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAMH;;;;;;;GAOG;AACH,MAAM,MAAM,cAAc,GACpB,mBAAmB,GACnB,kBAAkB,GAClB,YAAY,GACZ,QAAQ,CAAC;AAEf;;GAEG;AACH,MAAM,WAAW,aAAa;IAC1B,wBAAwB;IACxB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,4BAA4B;IAC5B,uBAAuB,CAAC,EAAE;QAAE,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;IAC7C,uBAAuB;IACvB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,+BAA+B;IAC/B,MAAM,CAAC,EAAE,MAAM,IAAI,CAAC;IACpB,6BAA6B;IAC7B,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAC;IACjC,iCAAiC;IACjC,OAAO,CAAC,EAAE,MAAM,IAAI,CAAC;IACrB,kCAAkC;IAClC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,sBAAsB;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,sBAAsB;IACtB,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,oBAAoB;IACpB,IAAI,CAAC,EAAE,QAAQ,GAAG,iBAAiB,CAAC;IACpC,oBAAoB;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,wBAAwB;IACxB,CAAC,GAAG,EAAE,QAAQ,MAAM,EAAE,GAAG,MAAM,GAAG,SAAS,CAAC;CAC/C;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IACxB,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,KAAK,EAAE,KAAK,GAAG,IAAI,CAAC;CACvB;AASD;;GAEG;AACH,wBAAsB,UAAU,CAC5B,GAAG,EAAE,MAAM,EACX,OAAO,GAAE,IAAI,CAAC,aAAa,EAAE,KAAK,GAAG,yBAAyB,CAAM,GACrE,OAAO,CAAC,IAAI,CAAC,CAyKf;AAED;;GAEG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,WAAW,CAAC,EAAE,OAAO,CAAA;CAAO,GAAG,IAAI,CAUrF;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,GAAG,IAAI,CAO7C;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE;IAAE,EAAE,CAAC,EAAE,QAAQ,CAAA;CAAO,GAAG,IAAI,CAQhF;AAMD;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAEnD;AAED;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAQxD;AAMD,YAAY,EAAE,aAAa,IAAI,OAAO,EAAE,cAAc,IAAI,QAAQ,EAAE,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,240 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @flightdev/script - Agnostic Script Loading Optimization
|
|
3
|
+
*
|
|
4
|
+
* Control how third-party scripts load to improve Core Web Vitals.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { Script } from '@flightdev/script/react';
|
|
9
|
+
*
|
|
10
|
+
* // Load analytics after page is interactive
|
|
11
|
+
* <Script
|
|
12
|
+
* src="https://analytics.example.com/script.js"
|
|
13
|
+
* strategy="afterInteractive"
|
|
14
|
+
* />
|
|
15
|
+
*
|
|
16
|
+
* // Lazy load when visible
|
|
17
|
+
* <Script
|
|
18
|
+
* src="https://widget.example.com/embed.js"
|
|
19
|
+
* strategy="lazyOnload"
|
|
20
|
+
* />
|
|
21
|
+
* ```
|
|
22
|
+
*/
|
|
23
|
+
// ============================================================================
|
|
24
|
+
// Script Loader
|
|
25
|
+
// ============================================================================
|
|
26
|
+
const loadedScripts = new Set();
|
|
27
|
+
const loadingScripts = new Map();
|
|
28
|
+
/**
|
|
29
|
+
* Load a script programmatically
|
|
30
|
+
*/
|
|
31
|
+
export async function loadScript(src, options = {}) {
|
|
32
|
+
const { strategy = 'afterInteractive', onLoad, onError, id, async: asyncAttr = true, defer, type, nonce, ...dataAttrs } = options;
|
|
33
|
+
const scriptId = id || src;
|
|
34
|
+
// Already loaded
|
|
35
|
+
if (loadedScripts.has(scriptId)) {
|
|
36
|
+
onLoad?.();
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
// Currently loading
|
|
40
|
+
if (loadingScripts.has(scriptId)) {
|
|
41
|
+
return loadingScripts.get(scriptId);
|
|
42
|
+
}
|
|
43
|
+
const loadPromise = new Promise((resolve, reject) => {
|
|
44
|
+
const executeLoad = () => {
|
|
45
|
+
const script = document.createElement('script');
|
|
46
|
+
script.src = src;
|
|
47
|
+
if (id)
|
|
48
|
+
script.id = id;
|
|
49
|
+
if (asyncAttr)
|
|
50
|
+
script.async = true;
|
|
51
|
+
if (defer)
|
|
52
|
+
script.defer = true;
|
|
53
|
+
if (type)
|
|
54
|
+
script.type = type;
|
|
55
|
+
if (nonce)
|
|
56
|
+
script.nonce = nonce;
|
|
57
|
+
// Add data attributes
|
|
58
|
+
Object.entries(dataAttrs).forEach(([key, value]) => {
|
|
59
|
+
if (key.startsWith('data-') && typeof value === 'string') {
|
|
60
|
+
script.setAttribute(key, value);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
script.onload = () => {
|
|
64
|
+
loadedScripts.add(scriptId);
|
|
65
|
+
loadingScripts.delete(scriptId);
|
|
66
|
+
onLoad?.();
|
|
67
|
+
resolve();
|
|
68
|
+
};
|
|
69
|
+
script.onerror = () => {
|
|
70
|
+
loadingScripts.delete(scriptId);
|
|
71
|
+
const error = new Error(`Failed to load script: ${src}`);
|
|
72
|
+
onError?.(error);
|
|
73
|
+
reject(error);
|
|
74
|
+
};
|
|
75
|
+
document.body.appendChild(script);
|
|
76
|
+
};
|
|
77
|
+
// Apply loading strategy
|
|
78
|
+
switch (strategy) {
|
|
79
|
+
case 'beforeInteractive':
|
|
80
|
+
// Load immediately
|
|
81
|
+
executeLoad();
|
|
82
|
+
break;
|
|
83
|
+
case 'afterInteractive':
|
|
84
|
+
// Wait for DOM to be ready
|
|
85
|
+
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
|
86
|
+
executeLoad();
|
|
87
|
+
}
|
|
88
|
+
else {
|
|
89
|
+
document.addEventListener('DOMContentLoaded', executeLoad, { once: true });
|
|
90
|
+
}
|
|
91
|
+
break;
|
|
92
|
+
case 'lazyOnload':
|
|
93
|
+
// Wait for window load or use requestIdleCallback
|
|
94
|
+
if (document.readyState === 'complete') {
|
|
95
|
+
if ('requestIdleCallback' in window) {
|
|
96
|
+
requestIdleCallback(executeLoad, { timeout: 5000 });
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
setTimeout(executeLoad, 1);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
window.addEventListener('load', () => {
|
|
104
|
+
if ('requestIdleCallback' in window) {
|
|
105
|
+
requestIdleCallback(executeLoad, { timeout: 5000 });
|
|
106
|
+
}
|
|
107
|
+
else {
|
|
108
|
+
setTimeout(executeLoad, 1);
|
|
109
|
+
}
|
|
110
|
+
}, { once: true });
|
|
111
|
+
}
|
|
112
|
+
break;
|
|
113
|
+
case 'worker':
|
|
114
|
+
// Web Worker strategy using Partytown
|
|
115
|
+
// Creates script with type="text/partytown" for Partytown to pick up
|
|
116
|
+
const executeWorkerLoad = () => {
|
|
117
|
+
const script = document.createElement('script');
|
|
118
|
+
script.src = src;
|
|
119
|
+
// Check if Partytown is available
|
|
120
|
+
const hasPartytown = typeof window.partytown !== 'undefined';
|
|
121
|
+
if (hasPartytown) {
|
|
122
|
+
// Use Partytown - script runs in web worker
|
|
123
|
+
script.type = 'text/partytown';
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
// Fallback to async loading on main thread
|
|
127
|
+
script.async = true;
|
|
128
|
+
console.info('[flight-script] Partytown not available, loading on main thread:', src);
|
|
129
|
+
}
|
|
130
|
+
if (id)
|
|
131
|
+
script.id = id;
|
|
132
|
+
if (nonce)
|
|
133
|
+
script.nonce = nonce;
|
|
134
|
+
// Add data attributes
|
|
135
|
+
Object.entries(dataAttrs).forEach(([key, value]) => {
|
|
136
|
+
if (key.startsWith('data-') && typeof value === 'string') {
|
|
137
|
+
script.setAttribute(key, value);
|
|
138
|
+
}
|
|
139
|
+
});
|
|
140
|
+
script.onload = () => {
|
|
141
|
+
loadedScripts.add(scriptId);
|
|
142
|
+
loadingScripts.delete(scriptId);
|
|
143
|
+
onLoad?.();
|
|
144
|
+
resolve();
|
|
145
|
+
};
|
|
146
|
+
script.onerror = () => {
|
|
147
|
+
loadingScripts.delete(scriptId);
|
|
148
|
+
const error = new Error(`Failed to load script: ${src}`);
|
|
149
|
+
onError?.(error);
|
|
150
|
+
reject(error);
|
|
151
|
+
};
|
|
152
|
+
// Insert after Partytown script if available
|
|
153
|
+
const partytownScript = document.querySelector('script[src*="partytown"]');
|
|
154
|
+
if (partytownScript && partytownScript.parentNode) {
|
|
155
|
+
partytownScript.parentNode.insertBefore(script, partytownScript.nextSibling);
|
|
156
|
+
}
|
|
157
|
+
else {
|
|
158
|
+
document.head.appendChild(script);
|
|
159
|
+
}
|
|
160
|
+
// If using Partytown, the script is handled by the worker
|
|
161
|
+
// Consider it loaded immediately for our tracking
|
|
162
|
+
if (hasPartytown) {
|
|
163
|
+
loadedScripts.add(scriptId);
|
|
164
|
+
loadingScripts.delete(scriptId);
|
|
165
|
+
onLoad?.();
|
|
166
|
+
resolve();
|
|
167
|
+
}
|
|
168
|
+
};
|
|
169
|
+
// Wait for DOM ready before adding worker scripts
|
|
170
|
+
if (document.readyState === 'complete' || document.readyState === 'interactive') {
|
|
171
|
+
executeWorkerLoad();
|
|
172
|
+
}
|
|
173
|
+
else {
|
|
174
|
+
document.addEventListener('DOMContentLoaded', executeWorkerLoad, { once: true });
|
|
175
|
+
}
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
loadingScripts.set(scriptId, loadPromise);
|
|
180
|
+
return loadPromise;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* Preconnect to a domain for faster script loading
|
|
184
|
+
*/
|
|
185
|
+
export function preconnect(url, options = {}) {
|
|
186
|
+
if (typeof document === 'undefined')
|
|
187
|
+
return;
|
|
188
|
+
const link = document.createElement('link');
|
|
189
|
+
link.rel = 'preconnect';
|
|
190
|
+
link.href = new URL(url).origin;
|
|
191
|
+
if (options.crossOrigin) {
|
|
192
|
+
link.crossOrigin = 'anonymous';
|
|
193
|
+
}
|
|
194
|
+
document.head.appendChild(link);
|
|
195
|
+
}
|
|
196
|
+
/**
|
|
197
|
+
* DNS prefetch for a domain
|
|
198
|
+
*/
|
|
199
|
+
export function dnsPrefetch(url) {
|
|
200
|
+
if (typeof document === 'undefined')
|
|
201
|
+
return;
|
|
202
|
+
const link = document.createElement('link');
|
|
203
|
+
link.rel = 'dns-prefetch';
|
|
204
|
+
link.href = new URL(url).origin;
|
|
205
|
+
document.head.appendChild(link);
|
|
206
|
+
}
|
|
207
|
+
/**
|
|
208
|
+
* Preload a script without executing
|
|
209
|
+
*/
|
|
210
|
+
export function preloadScript(src, options = {}) {
|
|
211
|
+
if (typeof document === 'undefined')
|
|
212
|
+
return;
|
|
213
|
+
const link = document.createElement('link');
|
|
214
|
+
link.rel = 'preload';
|
|
215
|
+
link.as = options.as || 'script';
|
|
216
|
+
link.href = src;
|
|
217
|
+
document.head.appendChild(link);
|
|
218
|
+
}
|
|
219
|
+
// ============================================================================
|
|
220
|
+
// Utilities
|
|
221
|
+
// ============================================================================
|
|
222
|
+
/**
|
|
223
|
+
* Check if a script is already loaded
|
|
224
|
+
*/
|
|
225
|
+
export function isScriptLoaded(src) {
|
|
226
|
+
return loadedScripts.has(src);
|
|
227
|
+
}
|
|
228
|
+
/**
|
|
229
|
+
* Wait for a script to load
|
|
230
|
+
*/
|
|
231
|
+
export function waitForScript(src) {
|
|
232
|
+
if (loadedScripts.has(src)) {
|
|
233
|
+
return Promise.resolve();
|
|
234
|
+
}
|
|
235
|
+
if (loadingScripts.has(src)) {
|
|
236
|
+
return loadingScripts.get(src);
|
|
237
|
+
}
|
|
238
|
+
return loadScript(src);
|
|
239
|
+
}
|
|
240
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@flightdev/script",
|
|
3
|
+
"version": "0.0.2",
|
|
4
|
+
"description": "Agnostic script loading optimization with multiple strategies",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"files": [
|
|
7
|
+
"dist"
|
|
8
|
+
],
|
|
9
|
+
"exports": {
|
|
10
|
+
".": {
|
|
11
|
+
"types": "./dist/index.d.ts",
|
|
12
|
+
"import": "./dist/index.js"
|
|
13
|
+
},
|
|
14
|
+
"./react": {
|
|
15
|
+
"types": "./dist/components/react.d.ts",
|
|
16
|
+
"import": "./dist/components/react.js"
|
|
17
|
+
},
|
|
18
|
+
"./partytown": {
|
|
19
|
+
"types": "./dist/adapters/partytown.d.ts",
|
|
20
|
+
"import": "./dist/adapters/partytown.js"
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"flight",
|
|
25
|
+
"script",
|
|
26
|
+
"optimization",
|
|
27
|
+
"lazy-loading",
|
|
28
|
+
"defer",
|
|
29
|
+
"async",
|
|
30
|
+
"partytown",
|
|
31
|
+
"web-worker"
|
|
32
|
+
],
|
|
33
|
+
"author": "",
|
|
34
|
+
"license": "MIT",
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"react": ">=18.0.0",
|
|
37
|
+
"@builder.io/partytown": ">=0.10.0"
|
|
38
|
+
},
|
|
39
|
+
"peerDependenciesMeta": {
|
|
40
|
+
"react": {
|
|
41
|
+
"optional": true
|
|
42
|
+
},
|
|
43
|
+
"@builder.io/partytown": {
|
|
44
|
+
"optional": true
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
"devDependencies": {
|
|
48
|
+
"@types/node": "^22.10.1",
|
|
49
|
+
"@types/react": "^19.0.6",
|
|
50
|
+
"typescript": "^5.7.2"
|
|
51
|
+
},
|
|
52
|
+
"scripts": {
|
|
53
|
+
"build": "tsc",
|
|
54
|
+
"dev": "tsc --watch"
|
|
55
|
+
}
|
|
56
|
+
}
|