@zoltanradics/async-script-loader 0.1.0

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/README.md ADDED
@@ -0,0 +1,216 @@
1
+ # Async Script Loader
2
+
3
+ A lightweight TypeScript library for dynamically loading external JavaScript files with promise-based API and automatic timeout handling.
4
+
5
+ ## Features
6
+
7
+ - Promise-based API for script loading
8
+ - Automatic timeout handling (2 second default)
9
+ - Proper event listener cleanup to prevent memory leaks
10
+ - URL encoding for query parameters
11
+ - TypeScript support with full type definitions
12
+ - Works in both ES modules and browser environments
13
+ - Small bundle size (~1 KB)
14
+
15
+ ## Why not use `import()`?
16
+
17
+ This library is **not** a replacement for the native `import()` function. They serve different purposes:
18
+
19
+ **Use `import()`** when:
20
+ - Loading ES modules with exports you need to access
21
+ - Working with your own modular code
22
+ - You need tree-shaking and modern module features
23
+
24
+ **Use this library** when:
25
+ - Loading third-party scripts that aren't ES modules (analytics, ads, legacy libraries)
26
+ - Scripts that set global variables or have side effects
27
+ - You need to append query parameters to the script URL
28
+ - Loading scripts that don't have exports (just execute code)
29
+ - You need timeout handling for unreliable external scripts
30
+ - Working with scripts designed to be loaded via `<script>` tags
31
+
32
+ **Example:** Google Analytics, payment SDKs, chat widgets, and many third-party services provide scripts meant to be loaded as `<script src="...">` rather than ES modules. This library makes loading such scripts programmatic and promise-based.
33
+
34
+ ## Installation
35
+
36
+ ```bash
37
+ npm install @zoltanradics/async-script-loader
38
+ ```
39
+
40
+ ## Usage
41
+
42
+ ### ES Module (Bundlers, Modern JavaScript)
43
+
44
+ ```javascript
45
+ import { asyncScriptLoader } from '@zoltanradics/async-script-loader';
46
+
47
+ // Load a script with query parameters
48
+ asyncScriptLoader('https://example.com/script.js', {
49
+ version: '1.0',
50
+ apiKey: 'your-api-key',
51
+ env: 'production'
52
+ })
53
+ .then(() => {
54
+ console.log('Script loaded successfully');
55
+ // Script is now available and can be used
56
+ })
57
+ .catch((error) => {
58
+ console.error('Failed to load script:', error);
59
+ });
60
+ ```
61
+
62
+ ### Direct Browser Usage (CDN)
63
+
64
+ ```html
65
+ <!DOCTYPE html>
66
+ <html>
67
+ <head>
68
+ <title>Async Script Loader Example</title>
69
+ </head>
70
+ <body>
71
+ <!-- Load from unpkg -->
72
+ <script src="https://unpkg.com/@zoltanradics/async-script-loader"></script>
73
+
74
+ <!-- Or load from jsDelivr -->
75
+ <!-- <script src="https://cdn.jsdelivr.net/npm/@zoltanradics/async-script-loader"></script> -->
76
+
77
+ <script>
78
+ // Access via global AsyncScriptLoader object
79
+ AsyncScriptLoader.asyncScriptLoader(
80
+ 'https://example.com/analytics.js',
81
+ { userId: '12345', tracking: 'enabled' }
82
+ )
83
+ .then(() => console.log('Analytics loaded'))
84
+ .catch((err) => console.error('Failed to load analytics', err));
85
+ </script>
86
+ </body>
87
+ </html>
88
+ ```
89
+
90
+ ### TypeScript
91
+
92
+ The library includes TypeScript definitions out of the box:
93
+
94
+ ```typescript
95
+ import { asyncScriptLoader } from '@zoltanradics/async-script-loader';
96
+
97
+ const loadScript = async (): Promise<void> => {
98
+ try {
99
+ await asyncScriptLoader('https://api.example.com/sdk.js', {
100
+ version: '2.0',
101
+ debug: 'true'
102
+ });
103
+ // Script loaded successfully
104
+ } catch (error) {
105
+ // Handle error
106
+ console.error(error);
107
+ }
108
+ };
109
+
110
+ loadScript();
111
+ ```
112
+
113
+ ## API
114
+
115
+ ### `asyncScriptLoader(baseUrl, queryParamObject)`
116
+
117
+ Dynamically injects a script tag into the document head and returns a Promise.
118
+
119
+ #### Parameters
120
+
121
+ - `baseUrl` (string): The base URL of the script to load
122
+ - `queryParamObject` (object): An object containing query parameters to append to the URL
123
+ - Keys and values will be automatically URL-encoded
124
+ - Example: `{ key: 'value', foo: 'bar' }` becomes `?key=value&foo=bar`
125
+
126
+ #### Returns
127
+
128
+ - `Promise<void>`: Resolves when the script loads successfully, rejects on error or timeout
129
+
130
+ #### Behavior
131
+
132
+ - The script is injected into the `<head>` element with `async` attribute
133
+ - Automatically times out after 2 seconds if the script hasn't loaded
134
+ - On timeout, the promise resolves (not rejects) with a console warning
135
+ - On error, the promise rejects with an error message
136
+ - Event listeners are automatically cleaned up after load/error/timeout
137
+
138
+ ## Examples
139
+
140
+ ### Loading Google Analytics
141
+
142
+ ```javascript
143
+ import { asyncScriptLoader } from '@zoltanradics/async-script-loader';
144
+
145
+ asyncScriptLoader('https://www.googletagmanager.com/gtag/js', {
146
+ id: 'G-XXXXXXXXXX'
147
+ })
148
+ .then(() => {
149
+ window.dataLayer = window.dataLayer || [];
150
+ function gtag() { dataLayer.push(arguments); }
151
+ gtag('js', new Date());
152
+ gtag('config', 'G-XXXXXXXXXX');
153
+ });
154
+ ```
155
+
156
+ ### Loading Multiple Scripts Sequentially
157
+
158
+ ```javascript
159
+ import { asyncScriptLoader } from '@zoltanradics/async-script-loader';
160
+
161
+ async function loadScripts() {
162
+ try {
163
+ await asyncScriptLoader('https://cdn.example.com/library.js', {});
164
+ console.log('Library loaded');
165
+
166
+ await asyncScriptLoader('https://cdn.example.com/plugin.js', {
167
+ theme: 'dark'
168
+ });
169
+ console.log('Plugin loaded');
170
+
171
+ // Both scripts are now loaded
172
+ } catch (error) {
173
+ console.error('Script loading failed:', error);
174
+ }
175
+ }
176
+
177
+ loadScripts();
178
+ ```
179
+
180
+ ### Loading Scripts in Parallel
181
+
182
+ ```javascript
183
+ import { asyncScriptLoader } from '@zoltanradics/async-script-loader';
184
+
185
+ Promise.all([
186
+ asyncScriptLoader('https://cdn.example.com/script1.js', {}),
187
+ asyncScriptLoader('https://cdn.example.com/script2.js', {}),
188
+ asyncScriptLoader('https://cdn.example.com/script3.js', {})
189
+ ])
190
+ .then(() => {
191
+ console.log('All scripts loaded successfully');
192
+ })
193
+ .catch((error) => {
194
+ console.error('One or more scripts failed to load:', error);
195
+ });
196
+ ```
197
+
198
+ ## Development
199
+
200
+ ```bash
201
+ # Install dependencies
202
+ npm install
203
+
204
+ # Start development server
205
+ npm run dev
206
+
207
+ # Build for production
208
+ npm run build
209
+
210
+ # Preview production build
211
+ npm run preview
212
+ ```
213
+
214
+ ## License
215
+
216
+ ISC
@@ -0,0 +1,3 @@
1
+ console.log('Success script loaded!');
2
+ window.exampleScriptLoaded = true;
3
+ window.exampleScriptLoadTime = new Date().toISOString();
@@ -0,0 +1,8 @@
1
+ // This script demonstrates reading query parameters
2
+ const scriptTag = document.currentScript;
3
+ const url = new URL(scriptTag.src);
4
+ const params = Object.fromEntries(url.searchParams);
5
+
6
+ console.log('Script loaded with query parameters:', params);
7
+ window.paramsReceived = params;
8
+ window.paramsScriptLoadTime = new Date().toISOString();
@@ -0,0 +1,5 @@
1
+ export declare function asyncScriptLoader(baseUrl: string, queryParamObject: {
2
+ [key: string]: string;
3
+ }): Promise<void>;
4
+
5
+ export { }
@@ -0,0 +1,27 @@
1
+ function f(c, t) {
2
+ const n = E(c, t), e = document.createElement("script");
3
+ e.src = n, e.async = !0;
4
+ const o = document.getElementsByTagName("head")[0];
5
+ return o ? (o.insertAdjacentElement("beforeend", e), new Promise(function(r, a) {
6
+ const m = setTimeout(() => {
7
+ d(), r(), console.warn(`${n} was loading for too long time.`);
8
+ }, 2e3), d = () => {
9
+ clearTimeout(m), e.removeEventListener("load", s), e.removeEventListener("error", u);
10
+ }, s = function(l) {
11
+ d(), r();
12
+ }, u = function(l) {
13
+ d(), a(new Error(`Failed to load ${n}.`));
14
+ };
15
+ e.addEventListener("load", s), e.addEventListener("error", u);
16
+ })) : Promise.reject(new Error("No <head> element found in document"));
17
+ }
18
+ function E(c, t) {
19
+ const i = Object.keys(t).reduce((n, e) => {
20
+ const o = encodeURIComponent(e), r = encodeURIComponent(t[e]);
21
+ return `${n}${n === "" ? "?" : "&"}${o}=${r}`;
22
+ }, "");
23
+ return `${c}${i}`;
24
+ }
25
+ export {
26
+ f as asyncScriptLoader
27
+ };
@@ -0,0 +1 @@
1
+ (function(n,o){typeof exports=="object"&&typeof module<"u"?o(exports):typeof define=="function"&&define.amd?define(["exports"],o):(n=typeof globalThis<"u"?globalThis:n||self,o(n.AsyncScriptLoader={}))})(this,(function(n){"use strict";function o(d,r){const t=l(d,r),e=document.createElement("script");e.src=t,e.async=!0;const c=document.getElementsByTagName("head")[0];return c?(c.insertAdjacentElement("beforeend",e),new Promise(function(i,f){const p=setTimeout(()=>{s(),i(),console.warn(`${t} was loading for too long time.`)},2e3),s=()=>{clearTimeout(p),e.removeEventListener("load",a),e.removeEventListener("error",m)},a=function(E){s(),i()},m=function(E){s(),f(new Error(`Failed to load ${t}.`))};e.addEventListener("load",a),e.addEventListener("error",m)})):Promise.reject(new Error("No <head> element found in document"))}function l(d,r){const u=Object.keys(r).reduce((t,e)=>{const c=encodeURIComponent(e),i=encodeURIComponent(r[e]);return`${t}${t===""?"?":"&"}${c}=${i}`},"");return`${d}${u}`}n.asyncScriptLoader=o,Object.defineProperty(n,Symbol.toStringTag,{value:"Module"})}));
package/package.json ADDED
@@ -0,0 +1,55 @@
1
+ {
2
+ "name": "@zoltanradics/async-script-loader",
3
+ "version": "0.1.0",
4
+ "description": "Async javascript loader",
5
+ "main": "./dist/index.umd.js",
6
+ "module": "./dist/index.es.js",
7
+ "types": "./dist/index.d.ts",
8
+ "unpkg": "./dist/index.umd.js",
9
+ "jsdelivr": "./dist/index.umd.js",
10
+ "exports": {
11
+ ".": {
12
+ "types": "./dist/index.d.ts",
13
+ "import": "./dist/index.es.js",
14
+ "require": "./dist/index.umd.js"
15
+ }
16
+ },
17
+ "files": [
18
+ "dist"
19
+ ],
20
+ "scripts": {
21
+ "dev": "vite",
22
+ "build": "vite build",
23
+ "preview": "vite preview",
24
+ "prepublishOnly": "npm run build",
25
+ "test": "echo \"Error: no test specified\" && exit 1"
26
+ },
27
+ "publishConfig": {
28
+ "access": "public"
29
+ },
30
+ "keywords": [
31
+ "javascript",
32
+ "dynamic-script",
33
+ "script-loader",
34
+ "promise",
35
+ "typescript",
36
+ "script-injection",
37
+ "async-script",
38
+ "cdn"
39
+ ],
40
+ "author": "Zoltan Radics",
41
+ "license": "ISC",
42
+ "repository": {
43
+ "type": "git",
44
+ "url": "git+https://github.com/zoltanradics/async-script-loader.git"
45
+ },
46
+ "homepage": "https://github.com/zoltanradics/async-script-loader#readme",
47
+ "bugs": {
48
+ "url": "https://github.com/zoltanradics/async-script-loader/issues"
49
+ },
50
+ "devDependencies": {
51
+ "typescript": "^5.9.3",
52
+ "vite": "^7.3.1",
53
+ "vite-plugin-dts": "^4.5.4"
54
+ }
55
+ }