dopant 5.0.2 → 6.0.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 +60 -31
- package/dist/index.cjs +41 -0
- package/package.json +17 -16
- package/src/index.js +49 -0
- package/dist/index.js +0 -50
- package/src/index.mjs +0 -56
package/README.md
CHANGED
|
@@ -1,31 +1,60 @@
|
|
|
1
|
-
The aerogel-weight & dead-simple resource loader 🚚
|
|
2
|
-
---
|
|
3
|
-
This package provides **lightweight** dynamic resource loader for
|
|
4
|
-
|
|
5
|
-
##
|
|
6
|
-
|
|
7
|
-
*
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
dopant
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
.
|
|
31
|
-
|
|
1
|
+
The aerogel-weight & dead-simple resource loader 🚚
|
|
2
|
+
---
|
|
3
|
+
This package provides a **lightweight** dynamic resource loader for web browsers.
|
|
4
|
+
|
|
5
|
+
## Abstract
|
|
6
|
+
|
|
7
|
+
* Promise-based API ⏳
|
|
8
|
+
* Parallel by default, ordered when required ⚡
|
|
9
|
+
* Supports all `<link>` relations (`preconnect`, `preload`, `stylesheet`, etc.) 🔗
|
|
10
|
+
* Supports all `<script>` types (`importmap`, `module`, `nomodule`, etc.) 📃
|
|
11
|
+
* Zero dependencies 🗽
|
|
12
|
+
|
|
13
|
+
## Prerequisites
|
|
14
|
+
|
|
15
|
+
* Node.js `>= 20.0.0`
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install dopant --save
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Usage
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
import dopant from 'dopant';
|
|
27
|
+
|
|
28
|
+
await dopant(
|
|
29
|
+
'/assets/css/layout.css',
|
|
30
|
+
'/assets/js/main.js',
|
|
31
|
+
['/assets/js/importmap.js', { type: 'importmap' }],
|
|
32
|
+
['/assets/js/module.js', { defer: true, type: 'module' }],
|
|
33
|
+
[
|
|
34
|
+
'/assets/webfonts/font.woff2',
|
|
35
|
+
{
|
|
36
|
+
as: 'font',
|
|
37
|
+
rel: 'preload',
|
|
38
|
+
type: 'font/woff2',
|
|
39
|
+
}
|
|
40
|
+
],
|
|
41
|
+
);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### API
|
|
45
|
+
|
|
46
|
+
#### `dopant(...resources)`
|
|
47
|
+
|
|
48
|
+
* `...resources` **{string | [string, attrs]}** Resources w/wo extra attributes to load into the web page
|
|
49
|
+
* **Returns:** Promise that resolves to a list of resolutions
|
|
50
|
+
|
|
51
|
+
### Behavior
|
|
52
|
+
|
|
53
|
+
* CSS files default to `rel="stylesheet"`
|
|
54
|
+
* If `rel` is provided, a `<link>` element is created
|
|
55
|
+
* Otherwise, a `<script>` element is created
|
|
56
|
+
* Scripts default to `async: true` (unless overridden or `defer: true` is set)
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
For more details, please check tests in the repository.
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _default = (...args) => {
|
|
8
|
+
return Promise.allSettled(args.map(async it => {
|
|
9
|
+
const [url, attrs = {}] = Array.isArray(it) ? it : [it];
|
|
10
|
+
if (url?.constructor !== String || attrs?.constructor !== Object) {
|
|
11
|
+
throw new TypeError('Invalid input');
|
|
12
|
+
}
|
|
13
|
+
const isLink = attrs.rel || /\.\bcss\b/i.test(url);
|
|
14
|
+
const el = document.createElement(isLink ? 'link' : 'script');
|
|
15
|
+
if (/\bimportmap\b|\bspeculationrules\b/i.test(attrs.type)) {
|
|
16
|
+
const res = await fetch(url);
|
|
17
|
+
if (!res.ok) {
|
|
18
|
+
throw new Error(`Failed to fetch importmap: ${url}`);
|
|
19
|
+
}
|
|
20
|
+
el.textContent = await res.text();
|
|
21
|
+
el.type = attrs.type;
|
|
22
|
+
document.head.append(el);
|
|
23
|
+
return el;
|
|
24
|
+
}
|
|
25
|
+
Object.assign(el, isLink ? {
|
|
26
|
+
...attrs,
|
|
27
|
+
href: url,
|
|
28
|
+
rel: attrs.rel || 'stylesheet'
|
|
29
|
+
} : {
|
|
30
|
+
...attrs,
|
|
31
|
+
async: attrs.async ?? !attrs.defer,
|
|
32
|
+
src: url
|
|
33
|
+
});
|
|
34
|
+
return new Promise((res, rej) => {
|
|
35
|
+
el.onerror = ev => (ev.target.remove(), rej(ev.target));
|
|
36
|
+
el.onload = ev => res(ev.target);
|
|
37
|
+
document.head.append(el);
|
|
38
|
+
});
|
|
39
|
+
}));
|
|
40
|
+
};
|
|
41
|
+
exports.default = _default;
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"author": {
|
|
3
|
-
"name": "Yehor Sergeenko",
|
|
4
3
|
"email": "yehor.sergeenko@gmail.com",
|
|
4
|
+
"name": "Yehor Sergeenko",
|
|
5
5
|
"url": "https://github.com/bricss"
|
|
6
6
|
},
|
|
7
7
|
"bugs": {
|
|
@@ -9,22 +9,21 @@
|
|
|
9
9
|
},
|
|
10
10
|
"description": "The aerogel-weight & dead-simple resource loader 🚚",
|
|
11
11
|
"devDependencies": {
|
|
12
|
-
"@babel/cli": "^7.28.
|
|
13
|
-
"@babel/core": "^7.
|
|
14
|
-
"@babel/
|
|
15
|
-
"@babel/preset-env": "^7.28.5",
|
|
12
|
+
"@babel/cli": "^7.28.6",
|
|
13
|
+
"@babel/core": "^7.29.0",
|
|
14
|
+
"@babel/preset-env": "^7.29.0",
|
|
16
15
|
"c8": "^10.1.3",
|
|
17
|
-
"eslint": "^
|
|
18
|
-
"eslint-config-ultra-refined": "^
|
|
16
|
+
"eslint": "^10.0.0",
|
|
17
|
+
"eslint-config-ultra-refined": "^4.0.1",
|
|
19
18
|
"mocha": "^11.7.5",
|
|
20
|
-
"playwright-chromium": "^1.
|
|
19
|
+
"playwright-chromium": "^1.58.2"
|
|
21
20
|
},
|
|
22
21
|
"engines": {
|
|
23
|
-
"node": ">=20.
|
|
22
|
+
"node": ">=20.0.0"
|
|
24
23
|
},
|
|
25
24
|
"exports": {
|
|
26
|
-
"import": "./src/index.
|
|
27
|
-
"require": "./dist/index.
|
|
25
|
+
"import": "./src/index.js",
|
|
26
|
+
"require": "./dist/index.cjs"
|
|
28
27
|
},
|
|
29
28
|
"files": [
|
|
30
29
|
"dist",
|
|
@@ -43,12 +42,14 @@
|
|
|
43
42
|
"url": "git+https://github.com/bricss/dopant.git"
|
|
44
43
|
},
|
|
45
44
|
"scripts": {
|
|
46
|
-
"build": "rm -rf dist && npx babel src -
|
|
47
|
-
"lint": "eslint",
|
|
48
|
-
"prepack": "npm run build",
|
|
45
|
+
"build": "rm -rf dist && npx babel src --out-dir dist --out-file-extension .cjs",
|
|
46
|
+
"lint": "eslint --concurrency=auto",
|
|
47
|
+
"prepack": "npm run build && sh misc.sh && npm run lint",
|
|
49
48
|
"pretest": "rm -rf coverage",
|
|
50
|
-
"test": "mocha
|
|
49
|
+
"test": "mocha",
|
|
50
|
+
"test:bail": "mocha --bail",
|
|
51
51
|
"test:cover": "npm test && c8 report --reporter=lcov --reporter=text"
|
|
52
52
|
},
|
|
53
|
-
"
|
|
53
|
+
"type": "module",
|
|
54
|
+
"version": "6.0.0"
|
|
54
55
|
}
|
package/src/index.js
ADDED
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
export default (...args) => {
|
|
2
|
+
return Promise.allSettled(
|
|
3
|
+
args.map(async (it) => {
|
|
4
|
+
const [url, attrs = {}] = Array.isArray(it) ? it : [it];
|
|
5
|
+
|
|
6
|
+
if (url?.constructor !== String || attrs?.constructor !== Object) {
|
|
7
|
+
throw new TypeError('Invalid input');
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const isLink = attrs.rel || /\.\bcss\b/i.test(url);
|
|
11
|
+
const el = document.createElement(isLink ? 'link' : 'script');
|
|
12
|
+
|
|
13
|
+
if (/\bimportmap\b|\bspeculationrules\b/i.test(attrs.type)) {
|
|
14
|
+
const res = await fetch(url);
|
|
15
|
+
|
|
16
|
+
if (!res.ok) {
|
|
17
|
+
throw new Error(`Failed to fetch importmap: ${ url }`);
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
el.textContent = await res.text();
|
|
21
|
+
el.type = attrs.type;
|
|
22
|
+
document.head.append(el);
|
|
23
|
+
|
|
24
|
+
return el;
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
Object.assign(
|
|
28
|
+
el,
|
|
29
|
+
isLink
|
|
30
|
+
? {
|
|
31
|
+
...attrs,
|
|
32
|
+
href: url,
|
|
33
|
+
rel: attrs.rel || 'stylesheet',
|
|
34
|
+
}
|
|
35
|
+
: {
|
|
36
|
+
...attrs,
|
|
37
|
+
async: attrs.async ?? !attrs.defer,
|
|
38
|
+
src: url,
|
|
39
|
+
},
|
|
40
|
+
);
|
|
41
|
+
|
|
42
|
+
return new Promise((res, rej) => {
|
|
43
|
+
el.onerror = (ev) => (ev.target.remove(), rej(ev.target));
|
|
44
|
+
el.onload = (ev) => res(ev.target);
|
|
45
|
+
document.head.append(el);
|
|
46
|
+
});
|
|
47
|
+
}),
|
|
48
|
+
);
|
|
49
|
+
};
|
package/dist/index.js
DELETED
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
|
4
|
-
value: true
|
|
5
|
-
});
|
|
6
|
-
exports.default = void 0;
|
|
7
|
-
var _default = (...args) => {
|
|
8
|
-
if (!args.length) {
|
|
9
|
-
throw new TypeError('Missing required arguments');
|
|
10
|
-
}
|
|
11
|
-
args = args.flat();
|
|
12
|
-
const {
|
|
13
|
-
head
|
|
14
|
-
} = document;
|
|
15
|
-
for (let i = 0, j = args.length - 1; i <= j; i++) {
|
|
16
|
-
const ext = args[i].split('?')[0].substring((~-args[i].lastIndexOf('.') >>> 0) + 2).toLowerCase();
|
|
17
|
-
let el;
|
|
18
|
-
if (ext === 'css') {
|
|
19
|
-
el = document.createElement('link');
|
|
20
|
-
el.href = args[i];
|
|
21
|
-
el.rel = 'stylesheet';
|
|
22
|
-
} else if (ext.match(/^c?js/)) {
|
|
23
|
-
el = document.createElement('script');
|
|
24
|
-
el.async = true;
|
|
25
|
-
el.src = args[i];
|
|
26
|
-
} else if (ext === 'mjs') {
|
|
27
|
-
el = document.createElement('script');
|
|
28
|
-
el.async = true;
|
|
29
|
-
el.src = args[i];
|
|
30
|
-
el.type = 'module';
|
|
31
|
-
} else {
|
|
32
|
-
args[i] = `Unsupported file type or extension: ${args[i]}`;
|
|
33
|
-
console.warn(args[i]);
|
|
34
|
-
}
|
|
35
|
-
args[i] = el && new Promise((resolve, reject) => {
|
|
36
|
-
el.onerror = ev => {
|
|
37
|
-
reject((head.removeChild(ev.target), ev));
|
|
38
|
-
};
|
|
39
|
-
el.onload = ev => {
|
|
40
|
-
resolve((ev.target.onload = ev.target.onerror = void 0, ev));
|
|
41
|
-
};
|
|
42
|
-
head.appendChild(el);
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
return Promise.allSettled(args).then(results => results.reduce((acc, val) => {
|
|
46
|
-
val.status === 'rejected' ? console.error(val.reason) : acc.push(val.value);
|
|
47
|
-
return acc;
|
|
48
|
-
}, []));
|
|
49
|
-
};
|
|
50
|
-
exports.default = _default;
|
package/src/index.mjs
DELETED
|
@@ -1,56 +0,0 @@
|
|
|
1
|
-
export default (...args) => {
|
|
2
|
-
if (!args.length) {
|
|
3
|
-
throw new TypeError('Missing required arguments');
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
args = args.flat();
|
|
7
|
-
|
|
8
|
-
const { head } = document;
|
|
9
|
-
|
|
10
|
-
for (let i = 0, j = args.length - 1; i <= j; i++) {
|
|
11
|
-
const ext = args[i]
|
|
12
|
-
.split('?')[0]
|
|
13
|
-
.substring((~-args[i].lastIndexOf('.') >>> 0) + 2)
|
|
14
|
-
.toLowerCase();
|
|
15
|
-
let el;
|
|
16
|
-
|
|
17
|
-
if (ext === 'css') {
|
|
18
|
-
el = document.createElement('link');
|
|
19
|
-
el.href = args[i];
|
|
20
|
-
el.rel = 'stylesheet';
|
|
21
|
-
} else if (ext.match(/^c?js/)) {
|
|
22
|
-
el = document.createElement('script');
|
|
23
|
-
el.async = true;
|
|
24
|
-
el.src = args[i];
|
|
25
|
-
} else if (ext === 'mjs') {
|
|
26
|
-
el = document.createElement('script');
|
|
27
|
-
el.async = true;
|
|
28
|
-
el.src = args[i];
|
|
29
|
-
el.type = 'module';
|
|
30
|
-
} else {
|
|
31
|
-
args[i] = `Unsupported file type or extension: ${ args[i] }`;
|
|
32
|
-
console.warn(args[i]);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
args[i] = el && new Promise((resolve, reject) => {
|
|
36
|
-
el.onerror = (ev) => {
|
|
37
|
-
reject((head.removeChild(ev.target), ev));
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
el.onload = (ev) => {
|
|
41
|
-
resolve((ev.target.onload = ev.target.onerror = void 0, ev));
|
|
42
|
-
};
|
|
43
|
-
|
|
44
|
-
head.appendChild(el);
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return Promise.allSettled(args)
|
|
49
|
-
.then((results) => results.reduce((acc, val) => {
|
|
50
|
-
val.status === 'rejected'
|
|
51
|
-
? console.error(val.reason)
|
|
52
|
-
: acc.push(val.value);
|
|
53
|
-
|
|
54
|
-
return acc;
|
|
55
|
-
}, []));
|
|
56
|
-
};
|