Skip to content

Commit

Permalink
feat: type improvements (#222)
Browse files Browse the repository at this point in the history
Co-authored-by: Pooya Parsa <pyapar@gmail.com>
  • Loading branch information
danielroe and pi0 committed Apr 22, 2021
1 parent 3b99ca9 commit 6dc8aa0
Show file tree
Hide file tree
Showing 26 changed files with 317 additions and 166 deletions.
6 changes: 6 additions & 0 deletions index.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { $Img } from './src/types'

declare global {
// Convenience declaration to avoid importing types into runtime templates
const $Img: $Img
}
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"vetur"
],
"scripts": {
"build": "siroc build && mkdist --src src/runtime --dist dist/runtime",
"build": "siroc build && mkdist --src src/runtime --dist dist/runtime -d",
"dev": "yarn nuxt playground",
"docs:build": "cd docs && nuxt generate",
"docs:dev": "yarn nuxt dev docs",
Expand Down Expand Up @@ -48,14 +48,17 @@
"@nuxt/typescript-build": "latest",
"@nuxt/typescript-runtime": "latest",
"@nuxtjs/eslint-config-typescript": "latest",
"@types/fs-extra": "^9.0.11",
"@types/jest": "latest",
"@types/lru-cache": "^5.1.0",
"@types/node-fetch": "^2.5.10",
"@vue/test-utils": "latest",
"babel-eslint": "latest",
"eslint": "latest",
"jest": "latest",
"jsdom": "latest",
"jsdom-global": "latest",
"mkdist": "latest",
"mkdist": "^0.2.0",
"nuxt": "latest",
"playwright": "latest",
"siroc": "latest",
Expand Down
6 changes: 3 additions & 3 deletions src/generate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,9 @@ import { hash, logger } from './utils'
const pipeline = promisify(stream.pipeline)

export function setupStaticGeneration (nuxt: any, options: ModuleOptions) {
const staticImages = {} // url ~> hashed file name
const staticImages: Record<string, string> = {} // url ~> hashed file name

nuxt.hook('vue-renderer:ssr:prepareContext', (renderContext) => {
nuxt.hook('vue-renderer:ssr:prepareContext', (renderContext: any) => {
renderContext.image = renderContext.image || {}
renderContext.image.mapToStatic = <MapToStatic> function ({ url, format }: ResolvedImage) {
if (!staticImages[url]) {
Expand Down Expand Up @@ -43,7 +43,7 @@ export function setupStaticGeneration (nuxt: any, options: ModuleOptions) {
})
}

async function downloadImage ({ url, name, outDir }) {
async function downloadImage ({ url, name, outDir }: { url: string, name: string, outDir: string }) {
try {
const response = await fetch(url)
if (!response.ok) { throw new Error(`Unexpected response ${response.statusText}`) }
Expand Down
6 changes: 4 additions & 2 deletions src/ipx.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
export function createIPXMiddleware (ipxOptions) {
const { createIPX, createIPXMiddleware } = require('ipx')
import type { IPXOptions } from 'ipx'

export function createIPXMiddleware (ipxOptions: IPXOptions) {
const { createIPX, createIPXMiddleware } = require('ipx') as typeof import('ipx')
const ipx = createIPX(ipxOptions)
return createIPXMiddleware(ipx)
}
24 changes: 14 additions & 10 deletions src/module.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,15 @@
import { resolve } from 'path'
import { resolve } from 'upath'

import type { Module } from '@nuxt/types'
import defu from 'defu'
import type { ModuleOptions, CreateImageOptions } from './types'
import { pick, pkg } from './utils'

import { setupStaticGeneration } from './generate'
import { resolveProviders, detectProvider } from './provider'
import { createIPXMiddleware } from './ipx'
import { resolveProviders, detectProvider } from './provider'
import type { ModuleOptions, CreateImageOptions } from './types'
import { pick, pkg } from './utils'

async function imageModule (moduleOptions: ModuleOptions) {
const imageModule: Module<ModuleOptions> = async function imageModule (moduleOptions) {
const { nuxt, addPlugin, addServerMiddleware } = this

const defaults: ModuleOptions = {
Expand Down Expand Up @@ -44,9 +47,10 @@ async function imageModule (moduleOptions: ModuleOptions) {
'intersectOptions'
])

options.static = options.static || {}
options.static.domains = options.domains

const providers = await resolveProviders(nuxt, options)
const providers = resolveProviders(nuxt, options)

// Run setup
for (const p of providers) {
Expand Down Expand Up @@ -87,17 +91,17 @@ async function imageModule (moduleOptions: ModuleOptions) {
setupStaticGeneration(nuxt, options)
})

const LruCache = require('lru-cache')
const LruCache = await import('lru-cache').then(r => r.default || r)
const cache = new LruCache()
nuxt.hook('vue-renderer:context', (ssrContext) => {
nuxt.hook('vue-renderer:context', (ssrContext: any) => {
ssrContext.cache = cache
})

nuxt.hook('listen', (_, listener) => {
nuxt.hook('listen', (_: any, listener: any) => {
options.internalUrl = `http://localhost:${listener.port}`
})
}

(imageModule as any).meta = pkg
; (imageModule as any).meta = pkg

export default imageModule
8 changes: 4 additions & 4 deletions src/provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,12 @@ export const providerSetup: Record<string, ProviderSetup> = {
await mkdirp(dirname(imagesConfig))
await writeJson(imagesConfig, {
domains: moduleOptions.domains,
sizes: Object.values(moduleOptions.screens)
sizes: Object.values(moduleOptions.screens || {})
})
}
}

export function resolveProviders (nuxt, options: ModuleOptions): ImageModuleProvider[] {
export function resolveProviders (nuxt: any, options: ModuleOptions): ImageModuleProvider[] {
const providers: ImageModuleProvider[] = []

for (const key in options) {
Expand Down Expand Up @@ -65,8 +65,8 @@ export function resolveProvider (nuxt: any, key: string, input: InputProvider):
return <ImageModuleProvider> {
...input,
setup,
runtime: normalize(input.provider),
importName: `${key}Runtime$${hash(input.provider, 4)}`,
runtime: normalize(input.provider!),
importName: `${key}Runtime$${hash(input.provider!, 4)}`,
runtimeOptions: input.options
}
}
Expand Down
44 changes: 30 additions & 14 deletions src/runtime/components/image.mixin.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import { parseSize } from '../utils'
import type { DefineMixin } from '../../types/vue'

const defineMixin: DefineMixin = (opts: any) => opts

// @vue/component
export const imageMixin = {
export const imageMixin = defineMixin({
props: {
// input source
src: { type: String, required: true },
Expand All @@ -9,13 +14,13 @@ export const imageMixin = {
quality: { type: [Number, String], default: undefined },
background: { type: String, default: undefined },
fit: { type: String, default: undefined },
modifiers: { type: Object, default: undefined },
modifiers: { type: Object as () => Record<string, any>, default: undefined },

// options
preset: { type: String, default: undefined },
provider: { type: String, default: undefined },

sizes: { type: [Object, String], default: undefined },
sizes: { type: [Object, String] as unknown as () => string | Record<string, any>, default: undefined },

// <img> attributes
width: { type: [String, Number], default: undefined },
Expand All @@ -25,41 +30,52 @@ export const imageMixin = {
usemap: { type: String, default: undefined },
longdesc: { type: String, default: undefined },
ismap: { type: Boolean, default: undefined },
crossorigin: { type: Boolean, default: undefined },
crossorigin: { type: [Boolean, String] as unknown as () => boolean | '' | 'anonymous' | 'use-credentials', default: undefined, validator: val => ['anonymous', 'use-credentials', '', true, false].includes(val) },
loading: { type: String, default: undefined },
decoding: { type: String, default: undefined }
decoding: { type: String as () => 'async' | 'auto' | 'sync', default: undefined, validator: val => ['async', 'auto', 'sync'].includes(val) }
},
computed: {
nImgAttrs () {
nImgAttrs (): {
width?: number
height?: number
alt?: string
referrerpolicy?: string
usemap?: string
longdesc?: string
ismap?: boolean
crossorigin?: '' | 'anonymous' | 'use-credentials'
loading?: string
decoding?: 'async' | 'auto' | 'sync'
} {
return {
width: this.width,
height: this.height,
width: parseSize(this.width),
height: parseSize(this.height),
alt: this.alt,
referrerpolicy: this.referrerpolicy,
usemap: this.usemap,
longdesc: this.longdesc,
ismap: this.ismap,
crossorigin: this.crossorigin,
crossorigin: this.crossorigin === true ? 'anonymous' : this.crossorigin || undefined,
loading: this.loading,
decoding: this.decoding
}
},
nModifiers () {
nModifiers (): { width?: number, height?: number, format?: string, quality?: string | number, background?: string, fit?: string } & Record<string, any> {
return {
...this.modifiers,
width: this.width,
height: this.height,
width: parseSize(this.width),
height: parseSize(this.height),
format: this.format,
quality: this.quality,
background: this.background,
fit: this.fit
}
},
nOptions () {
nOptions (): { provider?: string, preset?: string } {
return {
provider: this.provider,
preset: this.preset
}
}
}
}
})
24 changes: 17 additions & 7 deletions src/runtime/components/lazy.mixin.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import type { DefineMixin } from '../../types/vue'
import type { imageMixin } from './image.mixin'

import { useObserver } from '~image'

export const EMPTY_GIF = 'data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7'

const defineMixin: DefineMixin = (opts: any) => opts

interface PrivateThis {
_removeObserver?: ReturnType<typeof useObserver>
}

// @vue/component
export const lazyMixin = {
export const lazyMixin = defineMixin({
data () {
return {
lazyLoad: this.loading === 'lazy'
lazyLoad: (this as any as typeof imageMixin).loading === 'lazy'
}
},
mounted () {
Expand All @@ -19,15 +28,16 @@ export const lazyMixin = {
},
methods: {
observe () {
this._removeObserver = useObserver(this.$el, () => {
;(this as PrivateThis)._removeObserver = useObserver(this.$el, () => {
this.lazyLoad = false
})
},
unobserve () {
if (this._removeObserver) {
this._removeObserver()
delete this._removeObserver
const { _removeObserver } = this as PrivateThis
if (_removeObserver) {
_removeObserver()
delete (this as PrivateThis)._removeObserver
}
}
}
}
})
22 changes: 16 additions & 6 deletions src/runtime/components/nuxt-img.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,25 +7,34 @@
</template>

<script lang="ts">
import type { DefineComponentWithMixin } from '../../types/vue'
import type { ImageSizes } from '../../types'
import { imageMixin } from './image.mixin'
import { EMPTY_GIF, lazyMixin } from './lazy.mixin'
import { parseSize } from '~image'
export default {
const defineComponent: DefineComponentWithMixin = (opts: any) => opts
type NAttrs = typeof imageMixin['nImgAttrs'] & {
sizes?: string
srcset?: string
}
export default defineComponent({
name: 'NuxtImg',
mixins: [imageMixin, lazyMixin],
computed: {
nAttrs () {
const attrs: any = this.nImgAttrs
nAttrs (): NAttrs {
const attrs: NAttrs = this.nImgAttrs
if (this.sizes) {
const { sizes, srcset } = this.nSizes
attrs.sizes = sizes
attrs.srcset = srcset
}
return attrs
},
nSrc () {
nSrc (): string {
if (this.lazyLoad) {
return EMPTY_GIF
}
Expand All @@ -34,7 +43,8 @@ export default {
}
return this.$img(this.src, this.nModifiers, this.nOptions)
},
nSizes () {
/* eslint-disable no-undef */
nSizes (): ImageSizes {
return this.$img.getSizes(this.src, {
...this.nOptions,
sizes: this.sizes,
Expand All @@ -55,5 +65,5 @@ export default {
}
}
}
}
})
</script>
Loading

0 comments on commit 6dc8aa0

Please sign in to comment.