├── .github └── FUNDING.yml ├── .gitignore ├── CHANGELOG.md ├── LICENSE ├── README.md ├── package.json ├── pnpm-lock.yaml ├── src └── index.ts ├── tsconfig.json └── vercel.json /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: cupcakearmy 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | .vscode 4 | docs -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to this project will be documented in this file. 4 | 5 | The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), 6 | and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). 7 | 8 | ## [Unreleased] 9 | 10 | ## [0.2.5] - 2021-12-26 11 | 12 | ### Changed 13 | 14 | - Updated docs. 15 | - remove `lodash` as dependency. 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Niccolo Borgioli 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > DEPRECATED 2 | > 3 | > See https://github.com/cloudinary-community/svelte-cloudinary 4 | > 5 | > The npm package will be transfered to them. 6 | 7 | # svelte-cloudinary 8 | 9 | ![dependencies](https://badgen.net/david/dep/cupcakearmy/svelte-cloudinary) 10 | ![downloads badge](https://badgen.net/npm/dt/svelte-cloudinary) 11 | ![types badge](https://badgen.net/npm/types/svelte-cloudinary) 12 | ![version badge](https://badgen.net/npm/v/svelte-cloudinary) 13 | ![minzip size badge](https://badgen.net/bundlephobia/minzip/svelte-cloudinary) 14 | 15 | This is a little library that aims at integrating and making it easier to use the svelte with [Cloudinary](https://cloudinary.com/). 16 | There is an [official integration coming](https://github.com/cloudinary/cloudinary-svelte), but it's not ready and for not does not work great for now (SSR e.g.). 17 | 18 | ## 🌈 Features 19 | 20 | - Fully typed and typescript compatible 21 | - [Tiny: `~30kb gzip`](https://bundlephobia.com/result?p=svelte-cloudinary) (Of which 99% is the cloudinary dep.) 22 | - Automatic **resizing** based on the DOM and applied CSS 23 | - Automatic **lazy loading** 24 | - Fully compatible with native cloudinary options 25 | - Sapper (SSR) compatible 26 | 27 | ## 🗂 [Docs](https://svelte-cloudinary.vercel.app/modules/_index_) 28 | 29 | ## ❓ Questions & More -> [Discussions](https://github.com/cupcakearmy/svelte-cloudinary/discussions) 30 | 31 | ## 🚀 Quickstart 32 | 33 | ```bash 34 | npm install svelte-cloudinary 35 | ``` 36 | 37 | ```svelte 38 | 46 | 47 | 54 | 55 | background 59 | ``` 60 | 61 | This will formulate the Cloudinary url and insert it into the `img.src` property. 62 | Also it will resize to the `img` object itself because we set `bind: true`. 63 | 64 | > ⚠️ In firefox if you want to use the `bind` option to automatically compute sizes you need to set `img { display: inline-block or block; }` otherwise there can be problems with `getComputedStyle`. 65 | 66 | ## ☁️ Cloudinary Setup 67 | 68 | If you want the use super handfull auto upload function (which I think will apply to everyone) you have to set configure a few settings first. 69 | 70 | - Settings -> Security -> Allowed fetch domains: Add your domain(s) from which the images are fetched from. 71 | - Settings -> Upload -> Auto upload mapping: Set the mapping for your domain and/or path 72 | 73 | ###### Example 74 | 75 | Immagine you want to serve an image with the url of: `https://api.example.org/images/elephants.png` 76 | 77 | 1. Settings -> Security -> Allowed fetch domains: Add `api.example.org` to the list. 78 | 2. Settings -> Upload -> Auto upload mapping:
Folder: `myimages`
URL prefix: `https://api.example.org/images/` 79 | 80 | Now you can use the auto upload funtion like this: 81 | 82 | ```svelte 83 | background 87 | ``` 88 | 89 | ## 🤔 Why an [action](https://svelte.dev/docs#use_action) and not component? 90 | 91 | Well components are great of course, but when we only need to set a `src` tags we can leverage the upsides of a svelte [action](https://svelte.dev/docs#use_action) 92 | 93 | What are benefits? 94 | 95 | - Native styling (Svelte for now does not allow easy styling of child components)
With an action we can easily use local styling beacuse we still have access to the `` element 96 | - Lightweight 97 | - Reusable and composable 98 | 99 | Downsides: 100 | 101 | - The src will not be set serverside, so also not in the initial server response. Which I believe is not that bad though for images. 102 | 103 | ## 👷 Sapper 104 | 105 | If you are using sapper you can initialize it once in your root `_layout.svelte`. 106 | 107 | ```svelte 108 | 115 | ``` 116 | 117 | ## 🤓 Key Concepts 118 | 119 | ### `lazy` 120 | 121 | ###### default `true` 122 | 123 | If images should use the [`Intersection Observer API`](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API) to lazy load. 124 | 125 | ### `step` 126 | 127 | ###### default `200` 128 | 129 | The `step` property helps reducing the amounts of transformations cloudinary need to perform and less credits being billed to you. 130 | 131 | How? Basically whenever we calculate the dynamic size of the image rendered on the DOM we will get very specific numbers depending on the device. 132 | 133 | With `step` we approximate the size needed to the nearset bigger multiple of `step`. 134 | 135 | ###### Example 136 | 137 | Imagine the same `` has the width of `420`,`470` and `1080` on an iPhone, Android and Laptop respectively. 138 | 139 | With a `step` size of e.g. `100` (``) they will become `500`, `500`, and `1100`. This will limit the ammount of transformations needed. 140 | 141 | ### `bind` 142 | 143 | With bind we can dynamically set the width and/or height of the transformed image depending of the rendered size. 144 | 145 | - `bind: this` The size of the `` element 146 | - `bind: el` The computed size of another element in the dom (useful for a carousel e.g.) 147 | - `bind: { width: this }` Only bind the width, leaving the height free. Also works with height of course 148 | - `bind: { width: '.wrapper' }` Finds the closest element that matches the selector and uses it for width. 149 | 150 | ##### Note 151 | 152 | If you provide a `bind` options (``) but no crop option, we will automatically add `crop: 'fill'` otherwise the image will not be resized by cloudinary. 153 | 154 | ###### TLDR; 155 | 156 | ```svelte 157 | 158 | 159 | 160 | ``` 161 | 162 | ## ⌨️ Examples 163 | 164 | ### Fixed size 165 | 166 | ```svelte 167 | 170 | ``` 171 | 172 | ### `bind` 173 | 174 | ```svelte 175 | 176 | 179 | ``` 180 | 181 | ```svelte 182 | 183 |
187 |
188 | ``` 189 | 190 | ```svelte 191 | 192 |
196 |
197 | ``` 198 | 199 | ### `options` 200 | 201 | Native cloudinary options. See [here for official docs](https://cloudinary.com/documentation/image_transformations) 202 | For a quick glance 203 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "svelte-cloudinary", 3 | "version": "0.2.5", 4 | "main": "./dist/index.js", 5 | "types": "./dist/index.d.ts", 6 | "files": [ 7 | "dist" 8 | ], 9 | "scripts": { 10 | "dev": "tsc -w", 11 | "build": "tsc", 12 | "prepublishOnly": "rm -rf dist && pnpm run build", 13 | "docs": "typedoc --out docs src" 14 | }, 15 | "devDependencies": { 16 | "typedoc": "^0.22.10", 17 | "typescript": "^4.5.4" 18 | }, 19 | "dependencies": { 20 | "cloudinary-core": "^2.12.0" 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /pnpm-lock.yaml: -------------------------------------------------------------------------------- 1 | lockfileVersion: 5.3 2 | 3 | specifiers: 4 | cloudinary-core: ^2.12.0 5 | typedoc: ^0.22.10 6 | typescript: ^4.5.4 7 | 8 | dependencies: 9 | cloudinary-core: 2.12.0 10 | 11 | devDependencies: 12 | typedoc: 0.22.10_typescript@4.5.4 13 | typescript: 4.5.4 14 | 15 | packages: 16 | 17 | /balanced-match/1.0.2: 18 | resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} 19 | dev: true 20 | 21 | /brace-expansion/1.1.11: 22 | resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} 23 | dependencies: 24 | balanced-match: 1.0.2 25 | concat-map: 0.0.1 26 | dev: true 27 | 28 | /cloudinary-core/2.12.0: 29 | resolution: {integrity: sha512-EXvnWuq3Ah6pZHB2vEfkrJ4tCGlccZo3xsmt1f+bmrB53jU42ZrnX+v8xKRMot9c/STSO7GPbxbhJQ/z/xRazg==} 30 | peerDependencies: 31 | lodash: '>=4.0' 32 | dev: false 33 | 34 | /concat-map/0.0.1: 35 | resolution: {integrity: sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=} 36 | dev: true 37 | 38 | /fs.realpath/1.0.0: 39 | resolution: {integrity: sha1-FQStJSMVjKpA20onh8sBQRmU6k8=} 40 | dev: true 41 | 42 | /glob/7.2.0: 43 | resolution: {integrity: sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==} 44 | dependencies: 45 | fs.realpath: 1.0.0 46 | inflight: 1.0.6 47 | inherits: 2.0.4 48 | minimatch: 3.0.4 49 | once: 1.4.0 50 | path-is-absolute: 1.0.1 51 | dev: true 52 | 53 | /inflight/1.0.6: 54 | resolution: {integrity: sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=} 55 | dependencies: 56 | once: 1.4.0 57 | wrappy: 1.0.2 58 | dev: true 59 | 60 | /inherits/2.0.4: 61 | resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} 62 | dev: true 63 | 64 | /jsonc-parser/3.0.0: 65 | resolution: {integrity: sha512-fQzRfAbIBnR0IQvftw9FJveWiHp72Fg20giDrHz6TdfB12UH/uue0D3hm57UB5KgAVuniLMCaS8P1IMj9NR7cA==} 66 | dev: true 67 | 68 | /lunr/2.3.9: 69 | resolution: {integrity: sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow==} 70 | dev: true 71 | 72 | /marked/3.0.8: 73 | resolution: {integrity: sha512-0gVrAjo5m0VZSJb4rpL59K1unJAMb/hm8HRXqasD8VeC8m91ytDPMritgFSlKonfdt+rRYYpP/JfLxgIX8yoSw==} 74 | engines: {node: '>= 12'} 75 | hasBin: true 76 | dev: true 77 | 78 | /minimatch/3.0.4: 79 | resolution: {integrity: sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==} 80 | dependencies: 81 | brace-expansion: 1.1.11 82 | dev: true 83 | 84 | /once/1.4.0: 85 | resolution: {integrity: sha1-WDsap3WWHUsROsF9nFC6753Xa9E=} 86 | dependencies: 87 | wrappy: 1.0.2 88 | dev: true 89 | 90 | /path-is-absolute/1.0.1: 91 | resolution: {integrity: sha1-F0uSaHNVNP+8es5r9TpanhtcX18=} 92 | engines: {node: '>=0.10.0'} 93 | dev: true 94 | 95 | /shiki/0.9.15: 96 | resolution: {integrity: sha512-/Y0z9IzhJ8nD9nbceORCqu6NgT9X6I8Fk8c3SICHI5NbZRLdZYFaB233gwct9sU0vvSypyaL/qaKvzyQGJBZSw==} 97 | dependencies: 98 | jsonc-parser: 3.0.0 99 | vscode-oniguruma: 1.6.1 100 | vscode-textmate: 5.2.0 101 | dev: true 102 | 103 | /typedoc/0.22.10_typescript@4.5.4: 104 | resolution: {integrity: sha512-hQYZ4WtoMZ61wDC6w10kxA42+jclWngdmztNZsDvIz7BMJg7F2xnT+uYsUa7OluyKossdFj9E9Ye4QOZKTy8SA==} 105 | engines: {node: '>= 12.10.0'} 106 | hasBin: true 107 | peerDependencies: 108 | typescript: 4.0.x || 4.1.x || 4.2.x || 4.3.x || 4.4.x || 4.5.x 109 | dependencies: 110 | glob: 7.2.0 111 | lunr: 2.3.9 112 | marked: 3.0.8 113 | minimatch: 3.0.4 114 | shiki: 0.9.15 115 | typescript: 4.5.4 116 | dev: true 117 | 118 | /typescript/4.5.4: 119 | resolution: {integrity: sha512-VgYs2A2QIRuGphtzFV7aQJduJ2gyfTljngLzjpfW9FoYZF6xuw1W0vW9ghCKLfcWrCFxK81CSGRAvS1pn4fIUg==} 120 | engines: {node: '>=4.2.0'} 121 | hasBin: true 122 | dev: true 123 | 124 | /vscode-oniguruma/1.6.1: 125 | resolution: {integrity: sha512-vc4WhSIaVpgJ0jJIejjYxPvURJavX6QG41vu0mGhqywMkQqulezEqEQ3cO3gc8GvcOpX6ycmKGqRoROEMBNXTQ==} 126 | dev: true 127 | 128 | /vscode-textmate/5.2.0: 129 | resolution: {integrity: sha512-Uw5ooOQxRASHgu6C7GVvUxisKXfSgW4oFlO+aa+PAkgmH89O3CXxEEzNRNtHSqtXFTl0nAC1uYj0GMSH27uwtQ==} 130 | dev: true 131 | 132 | /wrappy/1.0.2: 133 | resolution: {integrity: sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=} 134 | dev: true 135 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import { Cloudinary, Configuration, Transformation } from 'cloudinary-core' 2 | 3 | export type ElementOrString = HTMLElement | string 4 | export type Size = { width: number; height: number } 5 | export type BindType = ElementOrString | true 6 | export type BindObject = BindType | { width?: BindType; height?: BindType } 7 | 8 | export type InitParameters = { debug?: boolean } 9 | export type ImageParameters = { 10 | src: string 11 | options?: Transformation | Transformation.Options 12 | bind?: BindObject 13 | lazy?: boolean | IntersectionObserverInit 14 | step?: number 15 | } 16 | 17 | let cl: Cloudinary | null = null 18 | let DEBUG: boolean = false 19 | 20 | function log(...msg: any[]) { 21 | if (DEBUG) console.debug(...msg) 22 | } 23 | 24 | export function initialize(cloudinary: Configuration.Options, options: InitParameters = {}) { 25 | DEBUG = options.debug || false 26 | cl = Cloudinary.new(cloudinary) 27 | } 28 | 29 | const defaults: Transformation | Transformation.Options = { 30 | fetchFormat: 'auto', 31 | quality: 'auto', 32 | } 33 | 34 | function calculateApproxRealSize(size: string, step: number): number { 35 | const withRatio = (parseInt(size) * window.devicePixelRatio) | 0 36 | const approx = withRatio - (withRatio % step) + step 37 | log(`Size\t withRation=${withRatio} approx=${approx} step=${step}`) 38 | return approx 39 | } 40 | 41 | function getSizeOfElement(el: HTMLElement, step: number): Size { 42 | const styles = window.getComputedStyle(el) 43 | log('GetSizeOfElement', el, `width=${styles.width} height=${styles.height}`) 44 | return { 45 | width: calculateApproxRealSize(styles.width, step), 46 | height: calculateApproxRealSize(styles.height, step), 47 | } 48 | } 49 | 50 | function getSizeOfElementOrSelector(node: ElementOrString, elOrString: ElementOrString, step: number): Size { 51 | if (typeof elOrString === 'string') { 52 | const search = typeof node === 'string' ? window.document.querySelector(node) : node 53 | if (!search) throw new Error('Could not find element: ' + node) 54 | const closest = search.closest(elOrString) 55 | if (closest) return getSizeOfElement(closest, step) 56 | else throw new Error('Could not find element: ' + elOrString) 57 | } else { 58 | return getSizeOfElement(elOrString, step) 59 | } 60 | } 61 | 62 | export function image(node: HTMLImageElement, parameters: ImageParameters) { 63 | if (!parameters || !parameters.src) throw new Error('No url provided for cloudinary') 64 | 65 | let { src, options, bind, lazy, step } = parameters 66 | log('Image Declared', parameters) 67 | options = options ?? {} 68 | options.crop = options.crop ?? 'fill' 69 | step = step ?? 200 70 | lazy = lazy ?? true 71 | 72 | if (!cl) throw new Error('Cloudinary not initialized') 73 | if (!src) throw new Error('Src must be set in use:image') 74 | 75 | if (bind) { 76 | if (bind === true) { 77 | bind = node 78 | } 79 | if (!options.crop) options.crop = 'fill' 80 | 81 | if (bind instanceof Element) Object.assign(options, getSizeOfElement(bind, step)) 82 | else if (typeof bind === 'string') { 83 | Object.assign(options, getSizeOfElementOrSelector(node, bind, step)) 84 | } else if (typeof bind === 'object') { 85 | if (bind.width) { 86 | options.width = getSizeOfElementOrSelector(node, bind.width === true ? node : bind.width, step).width 87 | } 88 | if (bind.height) { 89 | options.height = getSizeOfElementOrSelector(node, bind.height === true ? node : bind.height, step).height 90 | } 91 | } 92 | } 93 | 94 | const all: Transformation | Transformation.Options = { ...defaults, ...options } 95 | const attrs: any = cl.imageTag(parameters.src, all).attributes() 96 | log('Attributes', attrs) 97 | const replace = () => (node.src = attrs.src) 98 | 99 | if (lazy && typeof IntersectionObserver !== 'undefined') { 100 | const options: IntersectionObserverInit = lazy === true ? { rootMargin: '25%', threshold: 0 } : lazy 101 | new IntersectionObserver((entries, observer) => { 102 | if (entries[0].isIntersecting) { 103 | observer.disconnect() 104 | replace() 105 | } 106 | }, options).observe(node) 107 | } else { 108 | replace() 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | /* Visit https://aka.ms/tsconfig.json to read more about this file */ 4 | 5 | /* Basic Options */ 6 | // "incremental": true, /* Enable incremental compilation */ 7 | "target": "es2018", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ 8 | "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ 9 | // "lib": [], /* Specify library files to be included in the compilation. */ 10 | // "allowJs": true, /* Allow javascript files to be compiled. */ 11 | // "checkJs": true, /* Report errors in .js files. */ 12 | // "jsx": "preserve", /* Specify JSX code generation: 'preserve', 'react-native', or 'react'. */ 13 | "declaration": true, /* Generates corresponding '.d.ts' file. */ 14 | // "declarationMap": true, /* Generates a sourcemap for each corresponding '.d.ts' file. */ 15 | // "sourceMap": true, /* Generates corresponding '.map' file. */ 16 | // "outFile": "./", /* Concatenate and emit output to single file. */ 17 | "outDir": "./dist", /* Redirect output structure to the directory. */ 18 | "rootDir": "./src", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */ 19 | // "composite": true, /* Enable project compilation */ 20 | // "tsBuildInfoFile": "./", /* Specify file to store incremental compilation information */ 21 | // "removeComments": true, /* Do not emit comments to output. */ 22 | // "noEmit": true, /* Do not emit outputs. */ 23 | // "importHelpers": true, /* Import emit helpers from 'tslib'. */ 24 | // "downlevelIteration": true, /* Provide full support for iterables in 'for-of', spread, and destructuring when targeting 'ES5' or 'ES3'. */ 25 | // "isolatedModules": true, /* Transpile each file as a separate module (similar to 'ts.transpileModule'). */ 26 | 27 | /* Strict Type-Checking Options */ 28 | "strict": true, /* Enable all strict type-checking options. */ 29 | // "noImplicitAny": true, /* Raise error on expressions and declarations with an implied 'any' type. */ 30 | // "strictNullChecks": true, /* Enable strict null checks. */ 31 | // "strictFunctionTypes": true, /* Enable strict checking of function types. */ 32 | // "strictBindCallApply": true, /* Enable strict 'bind', 'call', and 'apply' methods on functions. */ 33 | // "strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */ 34 | // "noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */ 35 | // "alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */ 36 | 37 | /* Additional Checks */ 38 | // "noUnusedLocals": true, /* Report errors on unused locals. */ 39 | // "noUnusedParameters": true, /* Report errors on unused parameters. */ 40 | // "noImplicitReturns": true, /* Report error when not all code paths in function return a value. */ 41 | // "noFallthroughCasesInSwitch": true, /* Report errors for fallthrough cases in switch statement. */ 42 | 43 | /* Module Resolution Options */ 44 | // "moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */ 45 | // "baseUrl": "./", /* Base directory to resolve non-absolute module names. */ 46 | // "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */ 47 | // "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */ 48 | // "typeRoots": [], /* List of folders to include type definitions from. */ 49 | // "types": [], /* Type declaration files to be included in compilation. */ 50 | // "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */ 51 | "esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */ 52 | // "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */ 53 | // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ 54 | 55 | /* Source Map Options */ 56 | // "sourceRoot": "", /* Specify the location where debugger should locate TypeScript files instead of source locations. */ 57 | // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ 58 | // "inlineSourceMap": true, /* Emit a single file with source maps instead of having a separate file. */ 59 | // "inlineSources": true, /* Emit the source alongside the sourcemaps within a single file; requires '--inlineSourceMap' or '--sourceMap' to be set. */ 60 | 61 | /* Experimental Options */ 62 | // "experimentalDecorators": true, /* Enables experimental support for ES7 decorators. */ 63 | // "emitDecoratorMetadata": true, /* Enables experimental support for emitting type metadata for decorators. */ 64 | 65 | /* Advanced Options */ 66 | "skipLibCheck": true, /* Skip type checking of declaration files. */ 67 | "forceConsistentCasingInFileNames": true /* Disallow inconsistently-cased references to the same file. */ 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /vercel.json: -------------------------------------------------------------------------------- 1 | { 2 | "cleanUrls": true 3 | } 4 | --------------------------------------------------------------------------------