Skip to content

Commit

Permalink
feat(import-wrappers): supports asynchronous loading of wrapped compo…
Browse files Browse the repository at this point in the history
…nent
  • Loading branch information
freddy38510 committed Jul 18, 2022
1 parent 77071ca commit 63f7983
Show file tree
Hide file tree
Showing 30 changed files with 889 additions and 149 deletions.
3 changes: 3 additions & 0 deletions .eslintrc.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,9 @@ module.exports = {
node: true,
'vue/setup-compiler-macros': true,
},
globals: {
__DEV__: 'readonly',
},
rules: {
'prettier/prettier': 'error',
'import/no-extraneous-dependencies': ['error', { devDependencies: true }],
Expand Down
6 changes: 3 additions & 3 deletions demo/views/import-wrappers/HydrateNeverDemo.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<script setup>
import { ref, defineAsyncComponent } from 'vue';
import { ref } from 'vue';
import HydrationState from '../../components/HydrationState.vue';
import { hydrateNever } from '../../../src';
const CounterComp = hydrateNever(
defineAsyncComponent(() => import('../../components/CounterComp.vue'))
const CounterComp = hydrateNever(() =>
import('../../components/CounterComp.vue')
);
const isHydrated = ref(false);
Expand Down
6 changes: 3 additions & 3 deletions demo/views/import-wrappers/HydrateOnInteractionDemo.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<script setup>
import { ref, defineAsyncComponent } from 'vue';
import { ref } from 'vue';
import HydrationState from '../../components/HydrationState.vue';
import { hydrateOnInteraction } from '../../../src';
const InputComp = hydrateOnInteraction(
defineAsyncComponent(() => import('../../components/InputComp.vue'))
const InputComp = hydrateOnInteraction(() =>
import('../../components/InputComp.vue')
);
const isHydrated = ref(false);
Expand Down
6 changes: 3 additions & 3 deletions demo/views/import-wrappers/HydrateWhenIdleDemo.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<script setup>
import { ref, defineAsyncComponent } from 'vue';
import { ref } from 'vue';
import HydrationState from '../../components/HydrationState.vue';
import { hydrateWhenIdle } from '../../../src';
const CounterComp = hydrateWhenIdle(
defineAsyncComponent(() => import('../../components/CounterComp.vue'))
const CounterComp = hydrateWhenIdle(() =>
import('../../components/CounterComp.vue')
);
const isHydrated = ref(false);
Expand Down
4 changes: 2 additions & 2 deletions demo/views/import-wrappers/HydrateWhenTriggeredDemo.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<script setup>
import { ref, defineAsyncComponent } from 'vue';
import { ref } from 'vue';
import HydrationState from '../../components/HydrationState.vue';
import { hydrateWhenTriggered } from '../../../src';
Expand All @@ -17,7 +17,7 @@ function onHydrated() {
}
const CounterComp = hydrateWhenTriggered(
defineAsyncComponent(() => import('../../components/CounterComp.vue')),
() => import('../../components/CounterComp.vue'),
triggered
);
</script>
Expand Down
6 changes: 3 additions & 3 deletions demo/views/import-wrappers/HydrateWhenVisibleDemo.vue
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<script setup>
import { ref, defineAsyncComponent } from 'vue';
import { ref } from 'vue';
import HydrationState from '../../components/HydrationState.vue';
import { hydrateWhenVisible } from '../../../src';
const CounterComp = hydrateWhenVisible(
defineAsyncComponent(() => import('../../components/CounterComp.vue'))
const CounterComp = hydrateWhenVisible(() =>
import('../../components/CounterComp.vue')
);
const isHydrated = ref(false);
Expand Down
118 changes: 62 additions & 56 deletions src/components/LazyHydrationWrapper.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { computed, toRef } from 'vue';
import { computed, defineComponent, markRaw, toRef } from 'vue';

import {
useLazyHydration,
Expand All @@ -8,71 +8,77 @@ import {
useHydrateWhenTriggered,
} from '../composables';

import { createHydrationWrapper } from '../utils';

const opts = {
props: {
whenIdle: {
default: false,
type: [Boolean, Number],
},
whenVisible: {
default: false,
type: [Boolean, Object],
},
onInteraction: {
default: false,
type: [Array, Boolean, String],
},
whenTriggered: {
default: undefined,
type: [Boolean, Object],
},
},
const normalizeSlot = (slotContent) => {
return slotContent.length === 1 ? slotContent[0] : slotContent;
};

export default createHydrationWrapper(
null,
(props) => {
const result = useLazyHydration();
export default markRaw(
defineComponent({
name: 'LazyHydrationWrapper',
inheritAttrs: false,
suspensible: false,
props: {
whenIdle: {
default: false,
type: [Boolean, Number],
},
whenVisible: {
default: false,
type: [Boolean, Object],
},
onInteraction: {
default: false,
type: [Array, Boolean, String],
},
whenTriggered: {
default: undefined,
type: [Boolean, Object],
},
},
emits: ['hydrated'],

if (!result.willPerformHydration) {
return result;
}
setup(props, { slots, emit }) {
const result = useLazyHydration();

if (props.whenIdle) {
useHydrateWhenIdle(
result,
props.whenIdle !== true ? props.whenIdle : undefined
);
}
if (!result.willPerformHydration) {
return () => normalizeSlot(slots.default());
}

if (props.whenVisible) {
useHydrateWhenVisible(
result,
props.whenVisible !== true ? props.whenVisible : undefined
);
}
result.onHydrated(() => emit('hydrated'));

if (props.onInteraction) {
let events;
if (props.whenIdle) {
useHydrateWhenIdle(
result,
props.whenIdle !== true ? props.whenIdle : undefined
);
}

if (props.onInteraction !== true) {
events = computed(() =>
Array.isArray(props.onInteraction)
? props.onInteraction
: [props.onInteraction]
if (props.whenVisible) {
useHydrateWhenVisible(
result,
props.whenVisible !== true ? props.whenVisible : undefined
);
}

useHydrateOnInteraction(result, events);
}
if (props.onInteraction) {
let events;

if (props.whenTriggered !== undefined) {
useHydrateWhenTriggered(result, toRef(props, 'whenTriggered'));
}
if (props.onInteraction !== true) {
events = computed(() =>
Array.isArray(props.onInteraction)
? props.onInteraction
: [props.onInteraction]
);
}

useHydrateOnInteraction(result, events);
}

return result;
},
opts
if (props.whenTriggered !== undefined) {
useHydrateWhenTriggered(result, toRef(props, 'whenTriggered'));
}

return () => normalizeSlot(slots.default());
},
})
);
10 changes: 5 additions & 5 deletions src/composables/useHydrateOnInteraction.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { flushPromises } from '@vue/test-utils';
import { expect, vi } from 'vitest';
import { h, ref } from 'vue';

import { withSetup, triggerEvent } from '../../test/utils';
import { withSSRSetup, triggerEvent } from '../../test/utils';

import useLazyHydration from './useLazyHydration';
import useHydrateOnInteraction from './useHydrateOnInteraction';
Expand All @@ -14,7 +14,7 @@ beforeEach(() => {
it('should hydrate on interaction with single root element', async () => {
const spyClick = vi.fn();

const { container } = await withSetup(() => {
const { container } = await withSSRSetup(() => {
const result = useLazyHydration();

useHydrateOnInteraction(result, ['click', 'focus']);
Expand All @@ -38,7 +38,7 @@ it('should hydrate on interaction with single root element', async () => {
it('should hydrate on interaction with multiple root elements', async () => {
const spyClick = vi.fn();

const { container } = await withSetup(() => {
const { container } = await withSSRSetup(() => {
const result = useLazyHydration();

useHydrateOnInteraction(result, ['click', 'focus']);
Expand All @@ -65,7 +65,7 @@ it('should hydrate on interaction with multiple root elements', async () => {
it('should remove listeners when component has been hydrated', async () => {
const spyClick = vi.fn();

const { container } = await withSetup(() => {
const { container } = await withSSRSetup(() => {
const result = useLazyHydration();

useHydrateOnInteraction(result, ['focus', 'select']);
Expand Down Expand Up @@ -95,7 +95,7 @@ it('should remove listeners when component has been hydrated', async () => {
it('should remove listeners when component has been unmounted', async () => {
const show = ref(true);

const { container } = await withSetup(() => {
const { container } = await withSSRSetup(() => {
const LazyComp = {
setup() {
const result = useLazyHydration();
Expand Down
10 changes: 5 additions & 5 deletions src/composables/useHydrateWhenIdle.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { expect, vi } from 'vitest';
import { h, ref } from 'vue';

import { ensureMocksReset, requestIdleCallback } from '../../test/dom-mocks';
import { withSetup, triggerEvent } from '../../test/utils';
import { withSSRSetup, triggerEvent } from '../../test/utils';

import useLazyHydration from './useLazyHydration';
import useHydrateWhenIdle from './useHydrateWhenIdle';
Expand All @@ -23,7 +23,7 @@ afterEach(() => {
it('should hydrate when idle', async () => {
const spyClick = vi.fn();

const { container } = await withSetup(() => {
const { container } = await withSSRSetup(() => {
const result = useLazyHydration();

useHydrateWhenIdle(result);
Expand All @@ -47,7 +47,7 @@ it('should hydrate when idle', async () => {
it('should cancel Idle Callback when component has been hydrated', async () => {
const spyCancelIdleCallback = vi.spyOn(window, 'cancelIdleCallback');

await withSetup(() => {
await withSSRSetup(() => {
const result = useLazyHydration();

useHydrateWhenIdle(result);
Expand All @@ -68,7 +68,7 @@ it('should cancel Idle Callback when component has been unmounted', async () =>

const show = ref(true);

await withSetup(() => {
await withSSRSetup(() => {
const LazyComp = {
setup() {
const result = useLazyHydration();
Expand Down Expand Up @@ -96,7 +96,7 @@ it('should hydrate when requestIdleCallback is unsupported', async () => {

const spyClick = vi.fn();

const { container } = await withSetup(() => {
const { container } = await withSSRSetup(() => {
const result = useLazyHydration();

useHydrateWhenIdle(result);
Expand Down
6 changes: 3 additions & 3 deletions src/composables/useHydrateWhenTriggered.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { flushPromises } from '@vue/test-utils';
import { expect, vi } from 'vitest';
import { h, ref } from 'vue';

import { withSetup, triggerEvent } from '../../test/utils';
import { withSSRSetup, triggerEvent } from '../../test/utils';

import useLazyHydration from './useLazyHydration';
import useHydrateWhenTriggered from './useHydrateWhenTriggered';
Expand All @@ -15,7 +15,7 @@ it('should hydrate when trigger is true', async () => {
const spyClick = vi.fn();
const trigger = ref(false);

const { container } = await withSetup(() => {
const { container } = await withSSRSetup(() => {
const result = useLazyHydration();

useHydrateWhenTriggered(result, trigger);
Expand All @@ -42,7 +42,7 @@ it('should unWatch trigger when component has been unmounted', async () => {

let spyHydrate;

await withSetup((isClient) => {
await withSSRSetup((isClient) => {
const LazyComp = {
setup() {
const result = useLazyHydration();
Expand Down
11 changes: 6 additions & 5 deletions src/composables/useHydrateWhenVisible.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { expect, vi } from 'vitest';
import { h, ref } from 'vue';

import { ensureMocksReset, intersectionObserver } from '../../test/dom-mocks';
import { withSetup, triggerEvent } from '../../test/utils';
import { withSSRSetup, triggerEvent } from '../../test/utils';

import { createHydrationObserver } from '../utils';

import useLazyHydration from './useLazyHydration';
Expand All @@ -24,7 +25,7 @@ afterEach(() => {
it('should hydrate when single root element is visible', async () => {
const spyClick = vi.fn();

const { container } = await withSetup(() => {
const { container } = await withSSRSetup(() => {
const result = useLazyHydration();

useHydrateWhenVisible(result);
Expand Down Expand Up @@ -53,7 +54,7 @@ it('should hydrate when single root element is visible', async () => {
it('should hydrate when one of multiple root elements is visible', async () => {
const spyClick = vi.fn();

const { container } = await withSetup(() => {
const { container } = await withSSRSetup(() => {
const result = useLazyHydration();

useHydrateWhenVisible(result);
Expand Down Expand Up @@ -87,7 +88,7 @@ it('should hydrate when IntersectionObserver API is unsupported', async () => {

const spyClick = vi.fn();

const { container } = await withSetup(() => {
const { container } = await withSSRSetup(() => {
const result = useLazyHydration();

useHydrateWhenVisible(result);
Expand All @@ -108,7 +109,7 @@ it('should unobserve root elements when component has been unmounted', async ()
const { observer } = createHydrationObserver();
const spyUnobserve = vi.spyOn(observer, 'unobserve');

await withSetup(() => {
await withSSRSetup(() => {
const LazyComp = {
setup() {
const result = useLazyHydration();
Expand Down

0 comments on commit 63f7983

Please sign in to comment.