diff --git a/.circleci/config.yml b/.circleci/config.yml index 1db8443..a9fdaef 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -7,7 +7,7 @@ jobs: build: docker: # specify the version you desire here - - image: circleci/node:10.23.3 + - image: node:18.12 # Specify service dependencies here if necessary # CircleCI maintains a library of pre-built images @@ -26,11 +26,11 @@ jobs: # fallback to using the latest cache if no exact match is found - v1-dependencies- - - run: - name: Workaround for GoogleChrome/puppeteer#290 - command: 'sh .circleci/setup_puppeteer.sh' + # - run: + # name: Workaround for GoogleChrome/puppeteer#290 + # command: 'sh .circleci/setup_puppeteer.sh' - - run: yarn install + - run: npm install - save_cache: paths: @@ -38,5 +38,5 @@ jobs: key: v1-dependencies-{{ checksum "package.json" }} # run tests! - - run: yarn lint - - run: yarn test + - run: npm run lint + - run: npm run test diff --git a/.eslintrc b/.eslintrc index 1c0a62a..068d356 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,9 +1,20 @@ { - "extends": "standard", + "extends": [ + "standard", + "plugin:@typescript-eslint/recommended" + ], "env": { "browser": true, "es6": true, "jest": true, "mocha": true + }, + "parser": "@typescript-eslint/parser", + "rules": { + "@typescript-eslint/no-this-alias": 0, + "@typescript-eslint/ban-types": 0, + "prefer-rest-params": 0, + "@typescript-eslint/ban-ts-comment": 0, + "@typescript-eslint/no-empty-function": 0 } } \ No newline at end of file diff --git a/package.json b/package.json index abdc67e..9ad0201 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "unpkg": "vue-lazyload.js", "scripts": { "build": "node build", - "lint": "eslint ./src", + "lint": "eslint ./src/**/*.ts", "test": "jest" }, "dependencies": {}, @@ -35,12 +35,26 @@ "jest": { "setupFiles": [ "jest-canvas-mock" - ] + ], + "transform": { + "\\.[jt]sx?$": "ts-jest" + }, + "testEnvironment": "jsdom", + "testEnvironmentOptions": { + "customExportConditions": [ + "node", + "node-addons" + ] + } }, "devDependencies": { "@babel/plugin-syntax-dynamic-import": "^7.8.3", "@babel/preset-env": "^7.13.12", "@rollup/plugin-replace": "^2.4.2", + "@typescript-eslint/eslint-plugin": "^5.44.0", + "@typescript-eslint/parser": "^5.44.0", + "@vue/test-utils": "^2.2.4", + "assert": "^2.0.0", "assign-deep": "^1.0.1", "babel-cli": "^6.26.0", "babel-core": "^6.26.3", @@ -56,8 +70,9 @@ "eslint-plugin-node": "^11.1.0", "eslint-plugin-promise": "^4.3.1", "eslint-plugin-standard": "^5.0.0", - "jest": "^26.6.3", + "jest": "^29", "jest-canvas-mock": "^2.3.1", + "jest-environment-jsdom": "^29.3.1", "mocha": "^8.3.2", "rollup": "^2.43.1", "rollup-plugin-babel": "^2.6.1", @@ -66,6 +81,7 @@ "rollup-plugin-replace": "^2.2.0", "rollup-plugin-terser": "^7.0.2", "rollup-plugin-typescript": "^1.0.1", + "ts-jest": "^29.0.3", "tslib": "^2.1.0", "typescript": "^4.1.3", "vue": "^3.0.9" diff --git a/src/lazy-component.ts b/src/lazy-component.ts index 7c94223..2362ae5 100644 --- a/src/lazy-component.ts +++ b/src/lazy-component.ts @@ -19,7 +19,7 @@ export default (lazy: Lazy) => { } }, emits: ['show'], - setup(props, { emit, slots }) { + setup (props, { emit, slots }) { const el = ref() const state = reactive({ loaded: false, @@ -39,7 +39,7 @@ export default (lazy: Lazy) => { rect, checkInView, load, - state, + state } }) @@ -47,7 +47,7 @@ export default (lazy: Lazy) => { lazy.addLazyBox(vm.value) lazy.lazyLoadHandler() }) - + onUnmounted(() => { lazy.removeComponent(vm.value) }) @@ -61,4 +61,4 @@ export default (lazy: Lazy) => { ) } }) -} \ No newline at end of file +} diff --git a/src/lazy-container.ts b/src/lazy-container.ts index 2115dd0..1d27c1e 100644 --- a/src/lazy-container.ts +++ b/src/lazy-container.ts @@ -7,6 +7,7 @@ import Lazy from './lazy' export default class LazyContainerMananger { lazy: Lazy; + // eslint-disable-next-line no-use-before-define _queue: Array; constructor (lazy: Lazy) { this.lazy = lazy diff --git a/src/lazy-image.ts b/src/lazy-image.ts index 3373ae8..c51612a 100644 --- a/src/lazy-image.ts +++ b/src/lazy-image.ts @@ -22,13 +22,13 @@ export default (lazy: Lazy) => { src: TvalueFormatterParam, tag: string }>({ - setup(props,{ slots }) { + setup (props, { slots }) { const el = ref() const options = reactive({ - src: '', - error: '', - loading: '', - attempt: lazy.options.attempt + src: '', + error: '', + loading: '', + attempt: lazy.options.attempt }) const state = reactive({ loaded: false, @@ -58,7 +58,7 @@ export default (lazy: Lazy) => { rect, checkInView, load, - state, + state } }) @@ -80,7 +80,7 @@ export default (lazy: Lazy) => { } watch( - ()=> props.src, + () => props.src, () => { init() lazy.addLazyBox(vm.value) diff --git a/src/lazy.ts b/src/lazy.ts index 8cb2685..d41b56d 100644 --- a/src/lazy.ts +++ b/src/lazy.ts @@ -7,8 +7,6 @@ import { getDPR, scrollParent, getBestSelectionFromSrcset, - assign, - isObject, hasIntersectionObserver, modeType, ImageCache @@ -49,7 +47,6 @@ type Tlistener = { export type TvalueFormatterParam = string | Pick & { src: string } - class Lazy { version: string; mode: string; @@ -68,6 +65,7 @@ class Lazy { error: Array } }; + $on!: (event: TeventType, func: Function) => void; $once!: (event: TeventType, func: Function) => void $off!: (event: TeventType, func: Function) => void @@ -89,7 +87,7 @@ class Lazy { observerOptions }:VueLazyloadOptions) { this.version = '__VUE_LAZYLOAD_VERSION__' - this.lazyContainerMananger = null; + this.lazyContainerMananger = null this.mode = modeType.event this.ListenerQueue = [] this.TargetIndex = 0 @@ -256,7 +254,7 @@ class Lazy { * @param {Vue} vm Vue instance * @return */ - removeComponent (vm: Tlistener) { + removeComponent (vm: Tlistener) { if (!vm) return remove(this.ListenerQueue, vm) this._observer && this._observer.unobserve(vm.el) @@ -484,8 +482,7 @@ class Lazy { _valueFormatter ( value: TvalueFormatterParam - ) - { + ) { if (typeof value === 'object') { if (!value.src && !this.options.silent) console.error('Vue Lazyload warning: miss src with ' + value) return { @@ -504,4 +501,4 @@ class Lazy { } } -export default Lazy \ No newline at end of file +export default Lazy diff --git a/src/listener.ts b/src/listener.ts index 781f267..ec6cd7b 100644 --- a/src/listener.ts +++ b/src/listener.ts @@ -30,12 +30,14 @@ export default class ReactiveListener { loadStart: number; loadEnd: number; }; + state!: { loading: boolean; error: boolean; loaded: boolean; rendered: boolean; }; + rect: DOMRect; _imageCache: ImageCache; constructor ( @@ -115,7 +117,7 @@ export default class ReactiveListener { */ update (option: { src: string, loading: string, error: string }) { const oldSrc = this.src - this.src = option.src + this.src = option.src this.loading = option.loading this.error = option.error this.filter() diff --git a/src/useCheckInView.ts b/src/useCheckInView.ts index dd057b4..dde0493 100644 --- a/src/useCheckInView.ts +++ b/src/useCheckInView.ts @@ -22,4 +22,4 @@ export const useCheckInView = ( rect, checkInView } -} \ No newline at end of file +} diff --git a/src/util.ts b/src/util.ts index ab9762e..a05510f 100644 --- a/src/util.ts +++ b/src/util.ts @@ -5,7 +5,7 @@ const inBrowser = typeof window !== 'undefined' && window !== null export const hasIntersectionObserver = checkIntersectionObserver() -function checkIntersectionObserver(): boolean { +function checkIntersectionObserver (): boolean { if (inBrowser && 'IntersectionObserver' in window && 'IntersectionObserverEntry' in window && @@ -15,10 +15,10 @@ function checkIntersectionObserver(): boolean { if (!('isIntersecting' in window.IntersectionObserverEntry.prototype)) { Object.defineProperty(window.IntersectionObserverEntry.prototype, 'isIntersecting', { - get: function () { - return this.intersectionRatio > 0 - } - }) + get: function () { + return this.intersectionRatio > 0 + } + }) } return true } @@ -30,16 +30,16 @@ export const modeType = { observer: 'observer' } -function remove(arr: Array, item: any) { +function remove (arr: Array, item: any) { if (!arr.length) return const index = arr.indexOf(item) if (index > -1) return arr.splice(index, 1) } -function getBestSelectionFromSrcset(el: Element, scale: number): string { +function getBestSelectionFromSrcset (el: Element, scale: number): string { if (el.tagName !== 'IMG' || !el.getAttribute('data-srcset')) return '' - let options = el.getAttribute('data-srcset')!.trim().split(',') + const options = el.getAttribute('data-srcset')!.trim().split(',') const result: Array<[tmpWidth: number, tmpSrc: string]> = [] const container = el.parentNode as HTMLElement const containerWidth = container.offsetWidth * scale @@ -100,10 +100,10 @@ function getBestSelectionFromSrcset(el: Element, scale: number): string { const getDPR = (scale = 1): number => inBrowser ? (window.devicePixelRatio || scale) : scale // https://developers.google.com/speed/webp/faq#how_can_i_detect_browser_support_using_javascript -function supportWebp() { +function supportWebp () { if (!inBrowser) return false - let support: boolean = true + let support = true type TkTestImages = { lossy: string; @@ -111,7 +111,7 @@ function supportWebp() { alpha: string; animation: string; } - function checkWebpFeature(feature: keyof TkTestImages , callback: Function) { + function checkWebpFeature (feature: keyof TkTestImages, callback: Function) { const kTestImages: TkTestImages = { lossy: 'UklGRiIAAABXRUJQVlA4IBYAAAAwAQCdASoBAAEADsD+JaQAA3AAAAAA', lossless: 'UklGRhoAAABXRUJQVlA4TA0AAAAvAAAAEAcQERGIiP4HAA==', @@ -138,7 +138,7 @@ function supportWebp() { return support } -function throttle(action: Function, delay: number) { +function throttle (action: Function, delay: number) { let timeout: any = null let lastRun = 0 return function () { @@ -162,7 +162,7 @@ function throttle(action: Function, delay: number) { } } -function testSupportsPassive(): boolean { +function testSupportsPassive (): boolean { if (!inBrowser) return false let support = false try { @@ -179,7 +179,7 @@ function testSupportsPassive(): boolean { const supportsPassive = testSupportsPassive() const _ = { - on(el: Element, type: string, func: ()=>void, capture = false) { + on (el: Element, type: string, func: ()=>void, capture = false) { if (supportsPassive) { el.addEventListener(type, func, { capture: capture, @@ -189,7 +189,7 @@ const _ = { el.addEventListener(type, func, capture) } }, - off(el: Element, type: string, func: ()=>void, capture = false) { + off (el: Element, type: string, func: ()=>void, capture = false) { el.removeEventListener(type, func, capture) } } @@ -263,11 +263,11 @@ const scrollParent = (el:HTMLElement) => { return window } -function isObject(obj: any): boolean { +function isObject (obj: any): boolean { return obj !== null && typeof obj === 'object' } -function noop(): void { } +function noop (): void { } class ImageCache { max: number; diff --git a/test/test.spec.js b/test/test.spec.js index e632304..ab89495 100644 --- a/test/test.spec.js +++ b/test/test.spec.js @@ -1,7 +1,6 @@ import { mount } from '@vue/test-utils' import VueLazyload from '../src' -import genLazyCore from '../src/lazy' -import assert from 'assert' +import Lazy from '../src/lazy' import { createApp, inject } from 'vue' describe('VueLazyload.js Test Suite', function () { @@ -21,16 +20,13 @@ describe('VueLazyload.js Test Suite', function () { } }) - assert(wrapper.vm.Lazyload.mode, 'event') + expect(wrapper.vm.Lazyload.mode).toBe('event') }) it('_valueFormatter', function () { - const app = createApp(App) - const LazyCore = genLazyCore(app) - - const lazyload = new LazyCore({ - error: 'error', - loading: 'loading' + const lazyload = new Lazy({ + error: "error", + loading: "loading" }) expect(lazyload._valueFormatter('src').src).toBe('src') diff --git a/tsconfig.json b/tsconfig.json index fc13484..a0a970d 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,7 +2,8 @@ "strict": true, "compilerOptions": { "target": "es6", - "module": "es2015", + "module": "ES2015", + "allowJs": true, "moduleResolution": "node", "lib": [ "es5",