├── .editorconfig
├── .gitattributes
├── .gitignore
├── .npmignore
├── .travis.yml
├── LICENSE
├── demo
├── index.html
└── index.ts
├── package.json
├── readme.md
├── rollup.config.ts
├── src
├── loaders
│ ├── image-loader.ts
│ └── media-loader.ts
├── loaderz.ts
├── logger.ts
└── models
│ ├── loading-data.ts
│ ├── media-data.ts
│ └── resource-type.ts
├── test
├── helpers
│ ├── ImageMock.ts
│ ├── MediaMock.ts
│ └── setup-browser-env.js
├── image-loader.ts
└── media-loader.ts
├── tools
└── semantic-release-prepare.ts
├── tsconfig.json
├── tslint.json
└── yarn.lock
/.editorconfig:
--------------------------------------------------------------------------------
1 | #root = true
2 |
3 | [*]
4 | indent_style = space
5 | end_of_line = lf
6 | charset = utf-8
7 | trim_trailing_whitespace = true
8 | insert_final_newline = true
9 | max_line_length = 120
10 | indent_size = 2
11 |
12 | [*.md]
13 | trim_trailing_whitespace = false
14 |
--------------------------------------------------------------------------------
/.gitattributes:
--------------------------------------------------------------------------------
1 | *.* text eol=lf
2 |
3 | *.png binary
4 | *.jpg binary
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 |
4 | demo/dist
5 |
6 | yarn-error.log
7 | package-lock.json
8 |
9 | .cache
10 | .DS_Store
11 | .rpt2_cache
12 |
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | lib/
2 | test/
3 | demo/
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 |
3 | node_js:
4 | - lts/*
5 |
6 | cache:
7 | directories:
8 | - node_modules
9 | sudo: false
10 |
11 | script:
12 | - yarn test && yarn build
13 |
14 | notifications:
15 | email:
16 | on_success: never
17 | on_failure: never
18 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Thomas Cazade
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.
22 |
--------------------------------------------------------------------------------
/demo/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Loaderz dev-env
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/demo/index.ts:
--------------------------------------------------------------------------------
1 | // Consuming the module in your project would look like:
2 | // import { Loader } from 'loaderz';
3 | // tslint:disable:import-name
4 | import Loader, { Logger } from '../src/loaderz';
5 |
6 | // A list of heavy images to load, it could be art-assets for your HTML5 game
7 | const images = [
8 | 'https://images.unsplash.com/photo-1549360336-6a77ea5193eb',
9 | 'https://images.unsplash.com/photo-1549379458-e8f7034360a9',
10 | 'https://images.unsplash.com/photo-1548175850-b5a765959436',
11 | ];
12 |
13 | // Some audio elements to spice-up your HTML5 game
14 | const audios = [
15 | 'http://www.sample-videos.com/audio/mp3/crowd-cheering.mp3',
16 | 'http://www.sample-videos.com/audio/mp3/wave.mp3',
17 | ];
18 |
19 | // Instance the loader, you can easily implement it anywhere in your project
20 | const loader = new Loader();
21 |
22 | // Additionnal step, instanciate the Logger (this is not required for a normal
23 | // usage)
24 | const logger = new Logger();
25 |
26 | // Queue all our different resources (we can chain since)
27 | loader
28 | .queue('image', images)
29 | .queue('audio', audios);
30 |
31 | // Start loading the resources and have a full control of the loading state
32 | // using a promise and return a response with all elements loaded
33 | loader.start()
34 | .then(response => logger.log('All urls have been loaded, do whatever you want here:', response));
35 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "loaderz",
3 | "version": "1.2.0",
4 | "description": "A very easy-to-use asset-loader using promises. Support images, audios and videos.",
5 | "main": "dist/loaderz.umd.js",
6 | "module": "dist/loaderz.es5.js",
7 | "typings": "dist/types/loaderz.d.ts",
8 | "repository": {
9 | "type": "git",
10 | "url": "https://github.com/TotomInc/loaderz.git"
11 | },
12 | "scripts": {
13 | "prebuild": "rimraf dist",
14 | "build": "tsc --module commonjs && rollup -c rollup.config.ts",
15 | "demo": "rm -rf demo/dist && parcel demo/index.html -p 8080 -d demo/dist",
16 | "demo:build": "rm -rf demo/dist && parcel build demo/index.html -d demo/dist --public-url ./",
17 | "lint": "tslint --project tsconfig.json -t codeFrame 'src/**/*.ts'",
18 | "test": "NODE_ENV=test ava --verbose -s",
19 | "test:watch": "NODE_ENV=test ava --verbose --watch -s",
20 | "semantic-release": "semantic-release",
21 | "semantic-release-prepare": "ts-node tools/semantic-release-prepare"
22 | },
23 | "author": "TotomInc ",
24 | "license": "MIT",
25 | "bugs": {
26 | "url": "https://github.com/TotomInc/loaderz/issues"
27 | },
28 | "keywords": [
29 | "typescript",
30 | "promise",
31 | "asset-loader",
32 | "preloader",
33 | "game-utility"
34 | ],
35 | "homepage": "https://github.com/TotomInc/loaderz#readme",
36 | "devDependencies": {
37 | "@types/node": "^11.9.0",
38 | "ava": "^1.2.1",
39 | "browser-env": "^3.2.5",
40 | "colors": "^1.3.3",
41 | "husky": "^1.3.1",
42 | "lodash.camelcase": "^4.3.0",
43 | "parcel-bundler": "^1.11.0",
44 | "rimraf": "^2.6.3",
45 | "rollup": "^1.1.2",
46 | "rollup-plugin-commonjs": "^9.2.0",
47 | "rollup-plugin-json": "^3.1.0",
48 | "rollup-plugin-node-resolve": "^4.0.0",
49 | "rollup-plugin-sourcemaps": "^0.4.2",
50 | "rollup-plugin-typescript2": "^0.19.2",
51 | "semantic-release": "^15.13.3",
52 | "ts-node": "^8.0.2",
53 | "tslint": "^5.12.1",
54 | "tslint-config-airbnb": "^5.11.1",
55 | "typescript": "^3.3.3"
56 | },
57 | "files": [
58 | "dist"
59 | ],
60 | "ava": {
61 | "compileEnhancements": false,
62 | "require": [
63 | "ts-node/register",
64 | "./test/helpers/setup-browser-env.js"
65 | ],
66 | "extensions": [
67 | "ts"
68 | ]
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | [](https://travis-ci.org/TotomInc/loaderz) []() []() []()
6 |
7 | > A very easy-to-use asset-loader using promises. Supports images, audio and video. Fully documented for a perfect usage in your TypeScript projects.
8 |
9 | ## Installation
10 |
11 | Install using `yarn` or `npm`:
12 |
13 | - `yarn add loaderz`
14 | - `npm install loaderz --save`
15 |
16 | ## Usage
17 |
18 | ```typescript
19 | // Default export of Loaderz is the Loader.
20 | import Loader from 'loaderz';
21 |
22 | // A list of heavy images to load, it could be art-assets for your HTML5 game
23 | const images = [
24 | 'https://images.unsplash.com/photo-1549360336-6a77ea5193eb',
25 | 'https://images.unsplash.com/photo-1549379458-e8f7034360a9',
26 | 'https://images.unsplash.com/photo-1548175850-b5a765959436',
27 | ];
28 |
29 | // Some audio elements to spice-up your HTML5 game
30 | const audios = [
31 | 'http://www.sample-videos.com/audio/mp3/crowd-cheering.mp3',
32 | 'http://www.sample-videos.com/audio/mp3/wave.mp3',
33 | ];
34 |
35 | // Instanciate the loader, you can easily implement it anywhere in your project
36 | const loader = new Loader();
37 |
38 | // Queue all our different resources (we can chain since queue returns the
39 | // instance of loader)
40 | loader
41 | .queue('image', images)
42 | .queue('audio', audios);
43 |
44 | // Start loading the resources and have a full control of the global loading
45 | // state using a promise and return a response with all elements loaded
46 | loader.start()
47 | .then(response => console.log('All urls have been loaded, do whatever you want here:', response));
48 | ```
49 |
50 | ## Docs
51 |
52 | - `Loader#queue(type: string, src: string | string[])`: accepts 3 different types of medias (audio, image, video).
53 | - `Loader#start()`: used to load all the queued resources. Returns a global promise of the resources loading.
54 |
55 | - `Loader#queuedImages`: an array of URLs of images queued to load.
56 | - `Loader#queuedMedias`: an array of `MediaData` elements queued to load.
57 |
58 | ## Contribute
59 |
60 | All the code is written in TypeScript. Feel free to contribute by creating issues, PRs or suggesting new features:
61 |
62 | 1. Fork and clone the repo: `git@github.com:username/loaderz.git`
63 | 2. Install all dev-deps: `yarn install` or `npm install`
64 | 3. Run the demo: `yarn demo` (`localhost:8080`)
65 | 4. Edit some files
66 | 5. Run tests: `yarn test` or `npm test`
67 | - (optional) run `yarn lint` or `npm run lint` to automatically lint the files
68 | 6. Commit and push your edits on a separate branch
69 | 7. Create a PR which points on the `develop` branch
70 |
71 | ## License
72 |
73 | Under MIT license, view the license file for more informations.
74 |
--------------------------------------------------------------------------------
/rollup.config.ts:
--------------------------------------------------------------------------------
1 | import rollupPluginNodeResolve from 'rollup-plugin-node-resolve';
2 | import rollupPluginCommonjs from 'rollup-plugin-commonjs';
3 | import rollupPluginSourcemaps from 'rollup-plugin-sourcemaps';
4 | import lodashCamelcase from 'lodash.camelcase';
5 | import rollupPluginTypescript2 from 'rollup-plugin-typescript2';
6 | import rollupPluginJson from 'rollup-plugin-json';
7 |
8 | const pkg = require('./package.json');
9 |
10 | const libraryName = 'loaderz';
11 |
12 | export default {
13 | input: `src/${libraryName}.ts`,
14 | output: [
15 | { file: pkg.main, name: lodashCamelcase(libraryName), format: 'umd', sourcemap: true },
16 | { file: pkg.module, format: 'es', sourcemap: true },
17 | ],
18 |
19 | watch: {
20 | include: 'src/**',
21 | },
22 |
23 | plugins: [
24 | // Allow json resolution
25 | rollupPluginJson(),
26 |
27 | // Compile TypeScript files
28 | rollupPluginTypescript2({
29 | useTsconfigDeclarationDir: true,
30 | // By default we use `commonjs` in the `tsconfig`, we must use `es2015`
31 | // or `esnext` when bundling the module
32 | tsconfigOverride: {
33 | compilerOptions: {
34 | module: 'es2015',
35 | },
36 | },
37 | }),
38 |
39 | // Allow bundling cjs modules (unlike webpack, rollup doesn't understand cjs)
40 | rollupPluginCommonjs(),
41 |
42 | // Allow node_modules resolution, so you can use 'external' to control
43 | // which external modules to include in the bundle
44 | // https://github.com/rollup/rollup-plugin-node-resolve#usage
45 | rollupPluginNodeResolve(),
46 |
47 | // Resolve source maps to the original source
48 | rollupPluginSourcemaps(),
49 | ],
50 | };
51 |
--------------------------------------------------------------------------------
/src/loaders/image-loader.ts:
--------------------------------------------------------------------------------
1 | import { LoadingData } from '../models/loading-data';
2 |
3 | /**
4 | * The `ImageLoader` class make sure to pre-load an image URL by using the
5 | * `HTMLImageElement`. It creates a local `new Image()` with the specified URL
6 | * as a `src` and ensure it is entirely loaded or failed by using
7 | * `image.onload()` and `image.onerror()` events.
8 | */
9 | export class ImageLoader {
10 | /**
11 | * List of URLs to load when calling the `start()` function.
12 | */
13 | public urls: string[] = [];
14 |
15 | /**
16 | * Add URLs to load. Return an array of queued URLs to load.
17 | *
18 | * @param newURLs an array of URLs to add for the loading sequence
19 | * @returns an array of already queued URLs for the loading sequence
20 | */
21 | public queue(newURLs: string[]) {
22 | newURLs.forEach(url => this.urls.push(url));
23 |
24 | return this.urls;
25 | }
26 |
27 | /**
28 | * Start the loading of all URls registered, create an array of promises
29 | * generated by the `promise` function. Return a `Promise.all()` of all
30 | * image promises.
31 | *
32 | * @returns a `Promise.all()` of all image-promises
33 | */
34 | public start() {
35 | const promises = this.urls.map(url => this.promise(url));
36 |
37 | return Promise.all(promises);
38 | }
39 |
40 | /**
41 | * Create a dummy `HTMLImageElement` with the URL as the src attribute inside
42 | * a promise, that is resolved with the `image.onload` event or rejected with
43 | * the `image.onerror` event.
44 | *
45 | * @param url image-url to load
46 | * @returns the image-promise generated
47 | */
48 | private promise(url: string) {
49 | return new Promise((resolve, reject) => {
50 | const image = new Image();
51 |
52 | image.onload = () => resolve({ url, loaded: true, type: 'image' });
53 | image.onerror = () => reject({ url, loaded: false, type: 'image' });
54 | image.src = url;
55 | });
56 | }
57 | }
58 |
--------------------------------------------------------------------------------
/src/loaders/media-loader.ts:
--------------------------------------------------------------------------------
1 | import { LoadingData } from '../models/loading-data';
2 | import { MediaData } from '../models/media-data';
3 |
4 | /**
5 | * The `MediaLoader` class make sure to pre-load a media (video/audio) URL by
6 | * using the `HTMLAudioElement` or `HTMLVideoElement`. It creates a local
7 | * `new Audio()` or `new Video()` with the specified URL as a `src` and ensure
8 | * it is entirely loaded or failed by using `element.oncanplaythrough()` and
9 | * `element.onerror()` events.
10 | */
11 | export class MediaLoader {
12 | /**
13 | * Array of `MediaData` to load when calling the `start()` function.
14 | */
15 | public medias: MediaData[] = [];
16 |
17 | /**
18 | * Add URLs to load. Return an array of queued URLs to load.
19 | *
20 | * @param newURLs an array of URLs to add for the loading sequence
21 | * @returns an array of already queued URLs for the loading sequence
22 | */
23 | public queue(media: MediaData[]): void {
24 | media.forEach(media => this.medias.push(media));
25 | }
26 |
27 | /**
28 | * Start the loading of all URls registered, create an array of promises
29 | * generated by the `promise` function. Return a `Promise.all()` of all
30 | * media promises.
31 | *
32 | * @returns a `Promise.all()` of all media-promises
33 | */
34 | public start() {
35 | const promises = this.medias.map(media => this.promise(media));
36 |
37 | return Promise.all(promises);
38 | }
39 |
40 | /**
41 | * Create dummy `HTMLAudioElement` or `HTMLVideoElement` with the URL as the
42 | * src attribute inside a promise, that is resolved with the
43 | * `element.oncanplaythrough` event or rejected with the `element.onerror`
44 | * event.
45 | *
46 | * @param media media-data containing its type and the URL
47 | * @returns the media-promise generated
48 | */
49 | private promise(media: MediaData) {
50 | return new Promise((resolve, reject) => {
51 | const element = (media.type === 'audio')
52 | ? new Audio()
53 | : document.createElement('video');
54 |
55 | element.oncanplaythrough = () => resolve({ loaded: true, url: media.url, type: media.type });
56 | element.onerror = () => reject({ loaded: false, url: media.url, type: media.type });
57 | element.src = media.url;
58 | });
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/src/loaderz.ts:
--------------------------------------------------------------------------------
1 | import { LoadingData } from './models/loading-data';
2 | import { ResourceType } from './models/resource-type';
3 | import { MediaData } from './models/media-data';
4 | import { ImageLoader } from './loaders/image-loader';
5 | import { MediaLoader } from './loaders/media-loader';
6 | import { Logger } from './logger';
7 |
8 | class Loader {
9 | private logger: Logger;
10 | private imageLoader: ImageLoader;
11 | private mediaLoader: MediaLoader;
12 |
13 | constructor() {
14 | this.logger = new Logger();
15 |
16 | this.imageLoader = new ImageLoader();
17 | this.mediaLoader = new MediaLoader();
18 | }
19 |
20 | /**
21 | * Array of queued images URLs.
22 | */
23 | get queuedImages() {
24 | return this.imageLoader.urls;
25 | }
26 |
27 | /**
28 | * Array of queued media-data.
29 | */
30 | get queuedMedias() {
31 | return this.mediaLoader.medias;
32 | }
33 |
34 | /**
35 | * Add a new resource to the loading queue, automatically handle what type
36 | * of resource and how to load it.
37 | *
38 | * @param type type of the resource to load
39 | * @param src an url or array of urls to load
40 | * @returns returns the instance of itself
41 | */
42 | public queue(type: ResourceType, src: string | string[]): this {
43 | const urls = !Array.isArray(src) ? [src] : src;
44 |
45 | if (type === 'image') {
46 | this.imageLoader.queue(urls);
47 | } else if (type === 'audio' || type === 'video') {
48 | const medias: MediaData[] = [];
49 |
50 | urls.forEach(url => medias.push({ type, url }));
51 |
52 | this.mediaLoader.queue(medias);
53 | }
54 |
55 | return this;
56 | }
57 |
58 | /**
59 | * Start the loading sequence. Return an array of `LoadingData` to check the
60 | * status of loaded resources.
61 | */
62 | public start() {
63 | const allResources: LoadingData[] = [];
64 |
65 | return this.imageLoader.start()
66 | .then((res) => {
67 | const imagesNotLoaded = res.filter(status => !status.loaded);
68 |
69 | res.forEach(element => allResources.push(element));
70 |
71 | if (imagesNotLoaded.length > 0) {
72 | this.logger.warn('some image(s) have failed to load:', imagesNotLoaded);
73 | }
74 |
75 | return this.mediaLoader.start();
76 | })
77 | .then((res) => {
78 | const mediasNotLoaded = res.filter(status => !status.loaded);
79 |
80 | res.forEach(element => allResources.push(element));
81 |
82 | if (mediasNotLoaded.length > 0) {
83 | this.logger.warn('some media(s) have failed to load:', mediasNotLoaded);
84 | }
85 |
86 | return allResources;
87 | });
88 | }
89 | }
90 |
91 | export { Logger };
92 | export default Loader;
93 |
--------------------------------------------------------------------------------
/src/logger.ts:
--------------------------------------------------------------------------------
1 | /**
2 | * Alternative to the default `console.log()` but with extra styling to
3 | * differentiate logs from loaderz and something else. This is used internally
4 | * by Loaderz, but you can also use it by importing it from Loaderz.
5 | */
6 | export class Logger {
7 | private prefix: string;
8 |
9 | constructor(prefix: string = 'loaderz') {
10 | this.prefix = prefix;
11 | }
12 |
13 | /**
14 | * Log something in the console like you would do with `console.log()`, but
15 | * with extra styling.
16 | *
17 | * @param messages messages to send (includes variables)
18 | */
19 | public log(...messages: any[]) {
20 | const args: any[] = [].slice.call(messages);
21 |
22 | args.unshift(
23 | `%c[${this.prefix}]%c`,
24 | 'color: #57AE5B; font-weight: bold;',
25 | 'color: #05400A; font-weight: normal;',
26 | );
27 |
28 | console.log(...args);
29 | }
30 |
31 | /**
32 | * Log something in the console like you would do with `console.warn()`, but
33 | * with extra styling, with the warn background and a siren emoji.
34 | *
35 | * @param messages messages to send (includes variables)
36 | */
37 | public warn(...messages: any[]) {
38 | const args: any[] = [].slice.call(messages);
39 |
40 | args.unshift(
41 | `%c[${this.prefix}]%c 🚨`,
42 | 'color: #F6B93B; font-weight: bold;',
43 | 'color: #05400A; font-weight: normal;',
44 | );
45 |
46 | console.log(...args);
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/src/models/loading-data.ts:
--------------------------------------------------------------------------------
1 | export interface LoadingData {
2 | loaded: boolean;
3 | url: string;
4 | type: 'audio' | 'image' | 'video';
5 | }
6 |
--------------------------------------------------------------------------------
/src/models/media-data.ts:
--------------------------------------------------------------------------------
1 | export interface MediaData {
2 | url: string;
3 | type: 'audio' | 'video';
4 | }
5 |
--------------------------------------------------------------------------------
/src/models/resource-type.ts:
--------------------------------------------------------------------------------
1 | export type ResourceType = 'image' | 'audio' | 'video';
2 |
--------------------------------------------------------------------------------
/test/helpers/ImageMock.ts:
--------------------------------------------------------------------------------
1 | export class ImageMock {
2 | public src: string = '';
3 |
4 | // tslint:disable:variable-name
5 | private _onload: Function;
6 |
7 | // tslint:disable:variable-name
8 | private _onerror: Function;
9 |
10 | private fakeTime = 2000;
11 |
12 | constructor() {
13 | this._onload = () => {};
14 | this._onerror = () => {};
15 | }
16 |
17 | /**
18 | * When setting the `Image.onload`, store the handler into an internal
19 | * variable and instantly call the handler with a timeout to fake the
20 | * *fetching time*, so the promise won't be resolved instantly.
21 | */
22 | set onload(handler: Function) {
23 | this._onload = handler;
24 |
25 | setTimeout(() => handler(), this.fakeTime);
26 | }
27 |
28 | set onerror(handler: Function) {
29 | this._onerror = handler;
30 | }
31 |
32 | get onerror() {
33 | return this._onerror();
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/test/helpers/MediaMock.ts:
--------------------------------------------------------------------------------
1 | export class MediaMock {
2 | public src: string = '';
3 |
4 | // tslint:disable:variable-name
5 | private _oncanplaythrough: Function;
6 |
7 | // tslint:disable:variable-name
8 | private _onerror: Function;
9 |
10 | private fakeTime = 2000;
11 |
12 | constructor() {
13 | this._oncanplaythrough = () => {};
14 | this._onerror = () => {};
15 | }
16 |
17 | set oncanplaythrough(handler: Function) {
18 | this._oncanplaythrough = handler;
19 |
20 | setTimeout(() => handler(), this.fakeTime);
21 | }
22 |
23 | set onerror(handler: Function) {
24 | this._onerror = handler;
25 | }
26 |
27 | get onerror() {
28 | return this._onerror();
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/test/helpers/setup-browser-env.js:
--------------------------------------------------------------------------------
1 | import browserEnv from 'browser-env';
2 |
3 | /**
4 | * browser-env will add all global browser variables to the Node.js global
5 | * scope, creating a full browser environment. We can pass an array of global
6 | * browser globals if we know exactly what we need as a parameter of
7 | * `browserEnv`.
8 | */
9 | browserEnv(['window', 'document'], {
10 | resources: 'usable',
11 | });
12 |
--------------------------------------------------------------------------------
/test/image-loader.ts:
--------------------------------------------------------------------------------
1 | // tslint:disable:import-name
2 | import test from 'ava';
3 |
4 | import { ImageMock } from './helpers/ImageMock';
5 | import Loader from '../src/loaderz';
6 |
7 | /**
8 | * Before running all `ImageLoader` tests, we need to register the `ImageMock`
9 | * class globally, so it will take over the default `HTMLImageElement` used by
10 | * the `ImageLoader`. By doing this, we have a full control over the default
11 | * `Image` functions such as `onload` and `onerror`.
12 | */
13 | test.before((t) => {
14 | // @ts-ignore
15 | global.Image = ImageMock;
16 | });
17 |
18 | test('add an image URL to the image-loader array', (t) => {
19 | const loader = new Loader();
20 |
21 | loader.queue('image', 'https://example.com/image.jpg');
22 |
23 | t.is(loader.queuedImages.length, 1);
24 | });
25 |
26 | test('add an array of images URLs to the image-loader array', (t) => {
27 | const loader = new Loader();
28 | const urls = [
29 | 'https://example.com/image.jpg',
30 | 'https://example.com/image.png',
31 | 'https://example.com/image.gif',
32 | ];
33 |
34 | loader.queue('image', urls);
35 |
36 | t.is(loader.queuedImages.length, urls.length);
37 | t.deepEqual(loader.queuedImages, urls);
38 | });
39 |
40 | test('successfully load an image', async (t) => {
41 | const loader = new Loader();
42 |
43 | loader.queue('image', 'https://images.unsplash.com/photo-1549403610-177341eb0f67');
44 |
45 | const loaderResponse = await loader.start();
46 | const allLoaded = loaderResponse.every(element => element.loaded);
47 |
48 | t.true(allLoaded);
49 | t.is(loaderResponse.length, 1);
50 | });
51 |
52 | test('successfully load an array of images', async (t) => {
53 | const loader = new Loader();
54 | const urls = [
55 | 'https://example.com/image.jpg',
56 | 'https://example.com/image.png',
57 | 'https://example.com/image.gif',
58 | ];
59 |
60 | loader.queue('image', urls);
61 |
62 | const loaderResponse = await loader.start();
63 | const allLoaded = loaderResponse.every(element => element.loaded);
64 |
65 | t.true(allLoaded);
66 | t.is(loaderResponse.length, urls.length);
67 | });
68 |
--------------------------------------------------------------------------------
/test/media-loader.ts:
--------------------------------------------------------------------------------
1 | // tslint:disable:import-name
2 | import test from 'ava';
3 |
4 | import { MediaMock } from './helpers/MediaMock';
5 | import Loader from '../src/loaderz';
6 |
7 | /**
8 | * Before running all `MediaLoader` tests, we need to register the `MediaMock`
9 | * class globally, so it will take over the default `HTMLAudioElement` and
10 | * `HTMLVideoElement` used by the `MediaLoader`. By doing this, we have a full
11 | * control over the defaults `Audio` and `Media` classes functions such as
12 | * `oncanplaythrough` and `onerror`.
13 | */
14 | test.before((t) => {
15 | // @ts-ignore
16 | global.Audio = MediaMock;
17 | });
18 |
19 | test('add an audio URL to the media-loader array', (t) => {
20 | const loader = new Loader();
21 |
22 | loader.queue('audio', 'https://example.com/audio.mp3');
23 |
24 | t.is(loader.queuedMedias.length, 1);
25 | });
26 |
27 | test('add an array of audios URLs to the media-loader array', (t) => {
28 | const loader = new Loader();
29 | const urls = [
30 | 'https://example.com/audio.mp3',
31 | 'https://example.com/audio.wav',
32 | 'https://example.com/audio.flac',
33 | ];
34 |
35 | loader.queue('audio', urls);
36 |
37 | const queuedMediasAreAudios = loader.queuedMedias.every(media => media.type === 'audio');
38 |
39 | t.is(loader.queuedMedias.length, urls.length);
40 | t.true(queuedMediasAreAudios);
41 | });
42 |
43 | test('successfully load an audio', async (t) => {
44 | const loader = new Loader();
45 |
46 | loader.queue('audio', 'https://example.com/audio.mp3');
47 |
48 | const loaderResponse = await loader.start();
49 | const allLoaded = loaderResponse.every(element => element.loaded);
50 |
51 | t.true(allLoaded);
52 | t.is(loaderResponse.length, 1);
53 | });
54 |
55 | test('successfully load an array of audios URLs', async (t) => {
56 | const loader = new Loader();
57 | const urls = [
58 | 'https://example.com/audio.mp3',
59 | 'https://example.com/audio.wav',
60 | 'https://example.com/audio.flac',
61 | ];
62 |
63 | loader.queue('audio', urls);
64 |
65 | const loaderResponse = await loader.start();
66 | const allLoaded = loaderResponse.every(element => element.loaded);
67 |
68 | t.true(allLoaded);
69 | t.is(loaderResponse.length, urls.length);
70 | });
71 |
--------------------------------------------------------------------------------
/tools/semantic-release-prepare.ts:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const { fork } = require('child_process');
3 | const colors = require('colors');
4 |
5 | const { readFileSync, writeFileSync } = require('fs');
6 | const pkg = JSON.parse(
7 | readFileSync(path.resolve(__dirname, '..', 'package.json')),
8 | );
9 |
10 | pkg.scripts.prepush = 'npm run test:prod && npm run build';
11 | pkg.scripts.commitmsg = 'commitlint -E HUSKY_GIT_PARAMS';
12 |
13 | writeFileSync(
14 | path.resolve(__dirname, '..', 'package.json'),
15 | JSON.stringify(pkg, null, 2),
16 | );
17 |
18 | // Call husky to set up the hooks
19 | fork(path.resolve(__dirname, '..', 'node_modules', 'husky', 'lib', 'installer', 'bin'), ['install']);
20 |
21 | console.log();
22 | console.log(colors.green('Done!!'));
23 | console.log();
24 |
25 | if (pkg.repository.url.trim()) {
26 | console.log(colors.cyan('Now run:'));
27 | console.log(colors.cyan(' npm install -g semantic-release-cli'));
28 | console.log(colors.cyan(' semantic-release-cli setup'));
29 | console.log();
30 | console.log(
31 | colors.cyan('Important! Answer NO to "Generate travis.yml" question'),
32 | );
33 | console.log();
34 | console.log(
35 | colors.gray(
36 | 'Note: Make sure "repository.url" in your package.json is correct before',
37 | ),
38 | );
39 | } else {
40 | console.log(
41 | colors.red(
42 | 'First you need to set the "repository.url" property in package.json',
43 | ),
44 | );
45 | console.log(colors.cyan('Then run:'));
46 | console.log(colors.cyan(' npm install -g semantic-release-cli'));
47 | console.log(colors.cyan(' semantic-release-cli setup'));
48 | console.log();
49 | console.log(
50 | colors.cyan('Important! Answer NO to "Generate travis.yml" question'),
51 | );
52 | }
53 |
54 | console.log();
55 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "moduleResolution": "node",
4 | "target": "es5",
5 | "module": "commonjs",
6 | "lib": ["es2015", "es2016", "es2017", "dom"],
7 | "strict": true,
8 | "sourceMap": true,
9 | "declaration": true,
10 | "allowSyntheticDefaultImports": true,
11 | "experimentalDecorators": true,
12 | "emitDecoratorMetadata": true,
13 | "declarationDir": "dist/types",
14 | "outDir": "dist/lib",
15 | "typeRoots": ["node_modules/@types"]
16 | },
17 | "include": ["src"]
18 | }
19 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "tslint-config-airbnb",
3 | "rules": {
4 | "max-line-length": [false]
5 | }
6 | }
7 |
--------------------------------------------------------------------------------