├── test ├── mocha.opts └── tsconfig.json ├── tsconfig.json ├── LICENSE ├── src └── index.ts ├── package.json ├── README.md ├── .gitignore └── yarn.lock /test/mocha.opts: -------------------------------------------------------------------------------- 1 | --require ts-node-test-register 2 | -------------------------------------------------------------------------------- /test/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "declaration": false, 5 | "noEmit": true 6 | }, 7 | "include": [ 8 | "../src/**/*", 9 | "./**/*" 10 | ] 11 | } -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Basic Options */ 4 | "module": "ES2015", 5 | "moduleResolution": "node", 6 | "esModuleInterop": true, 7 | "newLine": "LF", 8 | "outDir": "./lib/", 9 | "target": "ES2015", 10 | "sourceMap": true, 11 | "declaration": true, 12 | "jsx": "preserve", 13 | "lib": [ 14 | "esnext", 15 | "dom" 16 | ], 17 | /* Strict Type-Checking Options */ 18 | "strict": true, 19 | /* Additional Checks */ 20 | /* Report errors on unused locals. */ 21 | "noUnusedLocals": true, 22 | /* Report errors on unused parameters. */ 23 | "noUnusedParameters": true, 24 | /* Report error when not all code paths in function return a value. */ 25 | "noImplicitReturns": true, 26 | /* Report errors for fallthrough cases in switch statement. */ 27 | "noFallthroughCasesInSwitch": true 28 | }, 29 | "include": [ 30 | "src/**/*" 31 | ], 32 | "exclude": [ 33 | ".git", 34 | "node_modules" 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 azu 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | const loadJs = (url: string): Promise => { 2 | const script = document.createElement("script"); 3 | script.src = url; 4 | document.querySelector("head")!.appendChild(script); 5 | return new Promise((resolve, reject): void => { 6 | script.addEventListener("load", () => { 7 | resolve(script); 8 | }); 9 | script.addEventListener("error", () => { 10 | reject(new Error(`Can not load: ${url}`)); 11 | }); 12 | }); 13 | }; 14 | 15 | const loadCSS = (url: string): Promise => { 16 | const link = document.createElement("link"); 17 | link.rel = "stylesheet"; 18 | link.href = url; 19 | document.querySelector("head")!.appendChild(link); 20 | return new Promise((resolve, reject): void => { 21 | link.addEventListener("load", () => { 22 | resolve(link); 23 | }); 24 | link.addEventListener("error", () => { 25 | reject(new Error(`Can not load: ${url}`)); 26 | }); 27 | }); 28 | }; 29 | 30 | export type Loader = (url: string) => Promise; 31 | 32 | export function createDynamicImportAssetsLoader(loader: Loader): (url: string) => Promise { 33 | const cacheMap = new Map(); 34 | return (url: string): Promise => { 35 | const cachedElement = cacheMap.get(url); 36 | if (cachedElement) { 37 | return Promise.resolve(cachedElement); 38 | } 39 | return loader(url).then((element) => { 40 | cacheMap.set(url, element); 41 | return element; 42 | }); 43 | }; 44 | } 45 | 46 | export const dynamicImportJS = createDynamicImportAssetsLoader((url) => loadJs(url)); 47 | export const dynamicImportCSS = createDynamicImportAssetsLoader((url) => loadCSS(url)); 48 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "dynamic-import-assets", 3 | "version": "1.1.0", 4 | "description": "Dynamic Import Assets like JavaScript and CSS.", 5 | "keywords": [ 6 | "browser", 7 | "import", 8 | "css", 9 | "js", 10 | "loader" 11 | ], 12 | "homepage": "https://github.com/azu/dynamic-import-assets", 13 | "bugs": { 14 | "url": "https://github.com/azu/dynamic-import-assets/issues" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/azu/dynamic-import-assets.git" 19 | }, 20 | "license": "MIT", 21 | "author": "azu", 22 | "source": "src/index.ts", 23 | "main": "dist/index.js", 24 | "umd:main": "dist/index.umd.js", 25 | "module": "dist/index.m.js", 26 | "types": "dist/index.d.ts", 27 | "sideEffects": false, 28 | "files": [ 29 | "dist/", 30 | "bin/" 31 | ], 32 | "scripts": { 33 | "build": "microbundle", 34 | "dev": "microbundle watch", 35 | "build:ts": "tsc -p .", 36 | "clean": "rimraf lib/", 37 | "prettier": "prettier --write \"**/*.{js,jsx,ts,tsx,css}\"", 38 | "prepublish": "npm run --if-present build", 39 | "test": "# mocha \"test/**/*.ts\"", 40 | "watch": "tsc -p . --watch" 41 | }, 42 | "husky": { 43 | "hooks": { 44 | "pre-commit": "lint-staged" 45 | } 46 | }, 47 | "lint-staged": { 48 | "*.{js,jsx,ts,tsx,css}": [ 49 | "prettier --write", 50 | "git add" 51 | ] 52 | }, 53 | "prettier": { 54 | "printWidth": 120, 55 | "singleQuote": false, 56 | "tabWidth": 4 57 | }, 58 | "devDependencies": { 59 | "@types/mocha": "^7.0.2", 60 | "@types/node": "^13.11.0", 61 | "cross-env": "^7.0.2", 62 | "husky": "^4.2.3", 63 | "lint-staged": "^10.1.1", 64 | "microbundle": "^0.11.0", 65 | "mocha": "^7.1.1", 66 | "prettier": "^2.0.2", 67 | "rimraf": "^3.0.2", 68 | "ts-node": "^8.8.1", 69 | "ts-node-test-register": "^8.0.1", 70 | "typescript": "^3.8.3" 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # dynamic-import-assets 2 | 3 | Dynamic Import Assets like JavaScript and CSS. 4 | 5 | ## Feature 6 | 7 | - Dynamic load JavaScript and CSS from URL 8 | - Support Promises 9 | - Work with ES modules registry like [UNPKG](https://unpkg.com/) and [Pika CDN](https://www.pika.dev/cdn) 10 | 11 | ## Install 12 | 13 | Install with [npm](https://www.npmjs.com/): 14 | 15 | npm install dynamic-import-assets 16 | 17 | 18 | ## Usage 19 | 20 | Provide these APIs 21 | 22 | - `dynamicImportJS`: Load JavaScript Script and resolve with loaded `