Skip to content

Commit

Permalink
feat(srcset): introduce sets props to create srcset
Browse files Browse the repository at this point in the history
  • Loading branch information
farnabaz committed Sep 8, 2020
1 parent 42bc98d commit e330900
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 49 deletions.
1 change: 1 addition & 0 deletions playground/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
src="local:/images/holly-pezant-FiwHZ935FLE-unsplash.jpg"
:width="300"
:height="400"
sets="300,410:600,800:900,900:1200"
/>
<nuxt-image
src="local+s50:/images/holly-pezant-FiwHZ935FLE-unsplash.jpg"
Expand Down
9 changes: 4 additions & 5 deletions src/module.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import path from 'path'
import { parse } from 'querystring'
import hash from 'hasha'

import { name, version } from '../package.json'
import { ModuleOptions, Provider, ProviderFactory } from './types'
import { ModuleOptions, ProviderFactory } from './types'

async function ImageModule (moduleOptions) {
const { nuxt, addServerMiddleware, addPlugin } = this
Expand All @@ -24,7 +23,7 @@ async function ImageModule (moduleOptions) {
options.presets.unshift({
name: 'lqip',
modifiers: {
contain: '20x20'
width: 20
}
})
}
Expand Down Expand Up @@ -98,14 +97,14 @@ async function ImageModule (moduleOptions) {
})
}
}
console.log(pluginOptions);

addPlugin({
fileName: 'image.js',
src: path.resolve(__dirname, '../templates/plugin.js'),
options: pluginOptions
})

// Transpile and alias auth src
// Transpile and alias image src
nuxt.options.alias['~image'] = __dirname
nuxt.options.build.transpile.push(__dirname)
}
Expand Down
8 changes: 8 additions & 0 deletions src/providers/cloudinary/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { ProviderFactory } from '../../types'

export default <ProviderFactory>function(providerOptions) {
return {
runtime: require.resolve('./runtime'),
runtimeOptions: providerOptions,
}
}
20 changes: 20 additions & 0 deletions src/providers/cloudinary/runtime.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { RuntimeProvider, ImageModifiers } from '../../types'

export default <RuntimeProvider> {
generateURL(src: string, modifiers: ImageModifiers, options: any) {
const operations = []

if (modifiers.width) {
operations.push('w_' + modifiers.width)
}
if (modifiers.height) {
operations.push('h_' + modifiers.height)
}
if (modifiers.resize) {
operations.push('c_' + modifiers.resize)
}

const operationsString = operations.join(',')
return options.baseURL + '/' + operationsString + src
}
}
5 changes: 2 additions & 3 deletions src/providers/local/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,8 @@ export default <RuntimeProvider> {
generateURL(src: string, modifiers: ImageModifiers, options: any) {
const operations = []

if (modifiers.contain) {
const [w, h] = modifiers.contain.split('x')
operations.push(`s_${w}_${h}`)
if (modifiers.width) {
operations.push(`w_${modifiers.width}`)
}
const operationsString = operations.length ? operations.join(',') : '_'
return options.baseURL + '/_/' + operationsString + src
Expand Down
7 changes: 5 additions & 2 deletions src/providers/twicpics/runtime.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@ import { RuntimeProvider, ImageModifiers } from '../../types'

export default <RuntimeProvider> {
generateURL(src: string, modifiers: ImageModifiers, options: any) {
const operations = Object.keys(modifiers)
.map(name => `${name}=${modifiers[name]}`)
const operations = []

if (modifiers.width || modifiers.height) {
operations.push(`resize=${modifiers.width || '-'}x${modifiers.height || '-'}`)
}

const operationsString = operations.join('/')
return options.baseURL + src + '?twic=v1/' + operationsString
Expand Down
10 changes: 5 additions & 5 deletions src/runtime/components/nuxt-image.css
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
transform: scale(1.1);
}

.__nuxt-image .fade-enter-active, .__nuxt-image .fade-leave-active {
transition: opacity 1s;
}

.__nuxt-image .fade-enter, .__nuxt-image .fade-leave-to /* .__nuxt-image .fade-leave-active below version 2.1.8 */ {
.__nuxt-image-original {
opacity: 0;
transition: opacity 400ms ease 0ms;
}
.__nuxt-image-original.visible {
opacity: 1;
}
102 changes: 68 additions & 34 deletions src/runtime/components/nuxt-image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,33 +21,68 @@ export default Vue.extend({
type: String,
default: ''
},
sets: {
type: [String, Array],
default: '',
}
},
data() {
return {
blury: null,
original: null,
srcset: [],
blurry: null,
loading: false,
loaded: false,
}
},
// @ts-ignore
async fetch() {
// this.$img[p]
// <NuxtImage src="cloudinary://..." src="{ path: '', provider: 'xnxx' }">
this.blury = await this.$img.lqip(this.src)
this.blurry = await this.$img.lqip(this.src)
},
mounted() {
this.$img.$observer.add(this.$el, () => {
console.log("OK, element is visible, Hoooray");
// OK, element is visible, Hoooray
this.loadOriginalImage()
})
},
computed: {
sizes() {
let sizes = this.sets;
if (typeof this.sets === 'string') {
sizes = this.sets.split(',').filter(Boolean).map((set) => {
let [breakpoint, width] = set.split(':').map(num => parseInt(num.trim(), 10))
return width ? {
breakpoint: `(min-width:${breakpoint}px) `,
width: width,
} : {
breakpoint: '',
width: breakpoint
}
})
}
if (!Array.isArray(sizes) || !sizes.length) {
sizes = [{
width: this.width
}]
}
sizes = sizes.map(size => ({ ...size, url: this.generateSizedImage(size.width) }))

return sizes;
},
generatedSrc() {
return this.sizes[0].url
},
generatedSrcset() {
return this.sizes.map(({ width, url }) => `${url} ${width}w`).join(', ')
},
generatedSizes() {
return this.sizes.map(({ width, breakpoint }) => `${breakpoint}${width}px`).reverse().join(', ')
}
},
beforeDestroy () {
this.$img.$observer.remove(this.$el)
},
watch: {
async src(v) {
this.blury = await this.$img.lqip(this.src)
this.blurry = await this.$img.lqip(this.src)
this.original = null
this.$img.$observer.remove(this.$el)
this.$img.$observer.add(this.$el, () => {
Expand All @@ -60,54 +95,53 @@ export default Vue.extend({
const bluryImage = h('img', {
class: '__nuxt-image-blur',
attrs: {
src: this.blury,
src: this.blurry,
alt: this.alt
}
})

let originalImage = null
if (this.original) {
originalImage = h('img', {
class: '__nuxt-image-original',
attrs: {
src: this.original,
alt: this.alt
const originalImage = h('img', {
class: ['__nuxt-image-original', this.loaded ? 'visible' : ''],
attrs: {
src: this.loading ? this.generatedSrc : undefined,
srcset: this.loading ? this.generatedSrcset : undefined,
sizes: this.loading ? this.generatedSizes : undefined,
alt: this.alt,
width: this.width,
height: this.height,
},
on: {
load: () => {
this.loaded = true
}
})
}
}
})


const transition = h('transition', {
props: {
name: 'fade'
const noScript = h('noscript', {
domProps: {
innerHTML: `<img class="__nuxt-image-original visible" src="${this.generatedSrc}" srcset="${this.generatedSrcset}" sizes="${this.generatedSizes}" width="${this.width}" height="${this.height}" alt="${this.alt}" >`
}
}, [originalImage])
}, [])

const wrapper = h('div', {
style: {
width: `${this.width}px`,
height: `${this.height}px`,
},
class: '__nuxt-image',
}, [bluryImage, transition])
}, [bluryImage, originalImage, noScript])

return wrapper;
},
methods: {
generateSourceImage() {
if (typeof this.src === "object") {
return this.$img(this.src);
}
generateSizedImage(width: number) {
return this.$img(this.src, {
resize: `${this.width}x${this.height}`
width: width
})
},
loadOriginalImage() {
var newImg = new Image();
newImg.onload = () => {
this.original = newImg.src
this.loaded = true
}
newImg.src = this.generateSourceImage();
this.loading = true
}
}
})
13 changes: 13 additions & 0 deletions src/runtime/image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -95,4 +95,17 @@ function createObserver() {
observer.unobserve(target)
}
}
}

async function readAsDataURI(url: string, host: string, encrypted: boolean) {
const _url = url.startsWith('http') ? url : `http${encrypted ? 's' : ''}://${host}$ url}`
const http = _url.startsWith('https') ? await import('https') : await import('http')
return await new Promise(async (resolve) => {
http.get(_url, (resp) => {
resp.setEncoding('base64');
let body = "data:" + resp.headers["content-type"] + ";base64,";
resp.on('data', (data) => { body += data });
resp.on('end', () => resolve(body));
}).on('error', (e) => resolve(url))
})
}
3 changes: 3 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,9 @@ export interface GenerateOptions {
}

export interface ImageModifiers {
width: number
height: number
resize: string
contain: string
}

Expand Down

0 comments on commit e330900

Please sign in to comment.