vue-lazy-hydration
Advanced tools
Comparing version 1.0.0-beta.4 to 1.0.0-beta.5
@@ -1,5 +0,72 @@ | ||
var isServer = typeof window === "undefined"; | ||
var isBrowser = !isServer; | ||
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { | ||
try { | ||
var info = gen[key](arg); | ||
var value = info.value; | ||
} catch (error) { | ||
reject(error); | ||
return; | ||
} | ||
if (info.done) { | ||
resolve(value); | ||
} else { | ||
Promise.resolve(value).then(_next, _throw); | ||
} | ||
} | ||
function _asyncToGenerator(fn) { | ||
return function () { | ||
var self = this, | ||
args = arguments; | ||
return new Promise(function (resolve, reject) { | ||
var gen = fn.apply(self, args); | ||
function _next(value) { | ||
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); | ||
} | ||
function _throw(err) { | ||
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); | ||
} | ||
_next(undefined); | ||
}); | ||
}; | ||
} | ||
function _defineProperty(obj, key, value) { | ||
if (key in obj) { | ||
Object.defineProperty(obj, key, { | ||
value: value, | ||
enumerable: true, | ||
configurable: true, | ||
writable: true | ||
}); | ||
} else { | ||
obj[key] = value; | ||
} | ||
return obj; | ||
} | ||
function _objectSpread(target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i] != null ? arguments[i] : {}; | ||
var ownKeys = Object.keys(source); | ||
if (typeof Object.getOwnPropertySymbols === 'function') { | ||
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { | ||
return Object.getOwnPropertyDescriptor(source, sym).enumerable; | ||
})); | ||
} | ||
ownKeys.forEach(function (key) { | ||
_defineProperty(target, key, source[key]); | ||
}); | ||
} | ||
return target; | ||
} | ||
var observers = new Map(); | ||
function createObserver(options) { | ||
@@ -15,4 +82,4 @@ if (typeof IntersectionObserver === "undefined") return null; | ||
var isIntersecting = entry.isIntersecting || entry.intersectionRatio > 0; | ||
if (!isIntersecting || !entry.target.parentElement.hydrate) return; | ||
entry.target.parentElement.hydrate(); | ||
if (!isIntersecting || !entry.target.hydrate) return; | ||
entry.target.hydrate(); | ||
}); | ||
@@ -23,3 +90,178 @@ }, options); | ||
} | ||
function loadingComponentFactory(resolvableComponent, options) { | ||
return _objectSpread({ | ||
render: function render(h) { | ||
var tag = this.$el ? this.$el.tagName : "div"; // eslint-disable-next-line no-underscore-dangle | ||
if (!this.$el) resolvableComponent._resolve(); | ||
return h(tag); | ||
} | ||
}, options); | ||
} | ||
function resolvableComponentFactory(component) { | ||
var resolve; | ||
var promise = new Promise(function (newResolve) { | ||
resolve = newResolve; | ||
}); // eslint-disable-next-line no-underscore-dangle | ||
promise._resolve = | ||
/*#__PURE__*/ | ||
_asyncToGenerator( | ||
/*#__PURE__*/ | ||
regeneratorRuntime.mark(function _callee() { | ||
return regeneratorRuntime.wrap(function _callee$(_context) { | ||
while (1) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
_context.t0 = resolve; | ||
if (!(typeof component === "function")) { | ||
_context.next = 7; | ||
break; | ||
} | ||
_context.next = 4; | ||
return component(); | ||
case 4: | ||
_context.t1 = _context.sent; | ||
_context.next = 8; | ||
break; | ||
case 7: | ||
_context.t1 = component; | ||
case 8: | ||
_context.t2 = _context.t1; | ||
(0, _context.t0)(_context.t2); | ||
case 10: | ||
case "end": | ||
return _context.stop(); | ||
} | ||
} | ||
}, _callee); | ||
})); | ||
return promise; | ||
} | ||
var isServer = typeof window === "undefined"; | ||
var isBrowser = !isServer; | ||
function hydrateWhenIdle(component, _ref) { | ||
var ignoredProps = _ref.ignoredProps; | ||
if (isServer) return component; | ||
var resolvableComponent = resolvableComponentFactory(component); | ||
var loading = loadingComponentFactory(resolvableComponent, { | ||
props: ignoredProps, | ||
mounted: function mounted() { | ||
// If `requestIdleCallback()` or `requestAnimationFrame()` | ||
// is not supported, hydrate immediately. | ||
if (!("requestIdleCallback" in window) || !("requestAnimationFrame" in window)) { | ||
// eslint-disable-next-line no-underscore-dangle | ||
resolvableComponent._resolve(); | ||
return; | ||
} | ||
var id = requestIdleCallback(function () { | ||
// eslint-disable-next-line no-underscore-dangle | ||
requestAnimationFrame(resolvableComponent._resolve); | ||
}, { | ||
timeout: this.idleTimeout | ||
}); | ||
var cleanup = function cleanup() { | ||
return cancelIdleCallback(id); | ||
}; | ||
resolvableComponent.then(cleanup); | ||
} | ||
}); | ||
return function () { | ||
return { | ||
component: resolvableComponent, | ||
delay: 0, | ||
loading: loading | ||
}; | ||
}; | ||
} | ||
function hydrateWhenVisible(component, _ref2) { | ||
var ignoredProps = _ref2.ignoredProps, | ||
observerOptions = _ref2.observerOptions; | ||
if (isServer) return component; | ||
var resolvableComponent = resolvableComponentFactory(component); | ||
var observer = createObserver(observerOptions); | ||
var loading = loadingComponentFactory(resolvableComponent, { | ||
props: ignoredProps, | ||
mounted: function mounted() { | ||
var _this = this; | ||
// If Intersection Observer API is not supported, hydrate immediately. | ||
if (!observer) { | ||
// eslint-disable-next-line no-underscore-dangle | ||
resolvableComponent._resolve(); | ||
return; | ||
} // eslint-disable-next-line no-underscore-dangle | ||
this.$el.hydrate = resolvableComponent._resolve; | ||
var cleanup = function cleanup() { | ||
return observer.unobserve(_this.$el); | ||
}; | ||
resolvableComponent.then(cleanup); | ||
observer.observe(this.$el); | ||
} | ||
}); | ||
return function () { | ||
return { | ||
component: resolvableComponent, | ||
delay: 0, | ||
loading: loading | ||
}; | ||
}; | ||
} | ||
function hydrateSsrOnly(component) { | ||
if (isServer) return component; | ||
var resolvableComponent = resolvableComponentFactory(component); | ||
var loading = loadingComponentFactory(resolvableComponent); | ||
return function () { | ||
return { | ||
component: resolvableComponent, | ||
delay: 0, | ||
loading: loading | ||
}; | ||
}; | ||
} | ||
function hydrateOnInteraction(component, _ref3) { | ||
var _ref3$event = _ref3.event, | ||
event = _ref3$event === void 0 ? "focus" : _ref3$event, | ||
ignoredProps = _ref3.ignoredProps; | ||
if (isServer) return component; | ||
var resolvableComponent = resolvableComponentFactory(component); | ||
var events = Array.isArray(event) ? event : [event]; | ||
var loading = loadingComponentFactory(resolvableComponent, { | ||
props: ignoredProps, | ||
mounted: function mounted() { | ||
var _this2 = this; | ||
events.forEach(function (eventName) { | ||
// eslint-disable-next-line no-underscore-dangle | ||
_this2.$el.addEventListener(eventName, resolvableComponent._resolve, { | ||
capture: true, | ||
once: true | ||
}); | ||
}); | ||
} | ||
}); | ||
return function () { | ||
return { | ||
component: resolvableComponent, | ||
delay: 0, | ||
loading: loading | ||
}; | ||
}; | ||
} | ||
var LazyHydrate = { | ||
@@ -69,3 +311,3 @@ props: { | ||
mounted: function mounted() { | ||
var _this = this; | ||
var _this3 = this; | ||
@@ -80,3 +322,3 @@ if (this.$el.childElementCount === 0) { | ||
this.interactionEvents.forEach(function (eventName) { | ||
_this.$el.addEventListener(eventName, _this.hydrate, { | ||
_this3.$el.addEventListener(eventName, _this3.hydrate, { | ||
capture: true, | ||
@@ -89,4 +331,4 @@ once: true | ||
this.interaction = function () { | ||
_this.interactionEvents.forEach(function (eventName) { | ||
return _this.$el.removeEventListener(eventName, _this.hydrate); | ||
_this3.interactionEvents.forEach(function (eventName) { | ||
return _this3.$el.removeEventListener(eventName, _this3.hydrate); | ||
}); | ||
@@ -106,3 +348,3 @@ }; | ||
requestAnimationFrame(function () { | ||
_this.hydrate(); | ||
_this3.hydrate(); | ||
}); | ||
@@ -131,4 +373,4 @@ }, { | ||
this.visible = function () { | ||
observer.unobserve(_this.$el); | ||
delete _this.$el.hydrate; | ||
observer.unobserve(_this3.$el); | ||
delete _this3.$el.hydrate; | ||
}; | ||
@@ -142,10 +384,10 @@ } | ||
cleanup: function cleanup() { | ||
var _this2 = this; | ||
var _this4 = this; | ||
var handlers = ["idle", "interaction", "visible"]; | ||
handlers.forEach(function (handler) { | ||
if (handler in _this2) { | ||
_this2[handler](); | ||
if (handler in _this4) { | ||
_this4[handler](); | ||
delete _this2[handler]; | ||
delete _this4[handler]; | ||
} | ||
@@ -179,1 +421,2 @@ }); | ||
export default LazyHydrate; | ||
export { hydrateWhenIdle, hydrateWhenVisible, hydrateSsrOnly, hydrateOnInteraction }; |
@@ -1,1 +0,1 @@ | ||
var isServer="undefined"==typeof window,isBrowser=!isServer,observers=new Map;function createObserver(e){if("undefined"==typeof IntersectionObserver)return null;var t=JSON.stringify(e);if(observers.has(t))return observers.get(t);var n=new IntersectionObserver(function(e){e.forEach(function(e){(e.isIntersecting||e.intersectionRatio>0)&&e.target.parentElement.hydrate&&e.target.parentElement.hydrate()})},e);return observers.set(t,n),n}var LazyHydrate={props:{idleTimeout:{default:2e3,type:Number},onInteraction:{type:[Array,Boolean,String]},ssrOnly:{type:Boolean},triggerHydration:{default:!1,type:Boolean},whenIdle:{type:Boolean},whenVisible:{type:[Boolean,Object]}},data:function(){return{hydrated:isServer}},watch:{triggerHydration:{immediate:!0,handler:function(e){e&&this.hydrate()}}},computed:{interactionEvents:function(){return this.onInteraction?!0===this.onInteraction?["focus"]:Array.isArray(this.onInteraction)?this.onInteraction:[this.onInteraction]:[]}},mounted:function(){var e=this;if(0!==this.$el.childElementCount){if(!this.ssrOnly){if(this.interactionEvents.forEach(function(t){e.$el.addEventListener(t,e.hydrate,{capture:!0,once:!0})}),this.interactionEvents.length&&(this.interaction=function(){e.interactionEvents.forEach(function(t){return e.$el.removeEventListener(t,e.hydrate)})}),this.whenIdle){if(!("requestIdleCallback"in window&&"requestAnimationFrame"in window))return void this.hydrate();var t=requestIdleCallback(function(){requestAnimationFrame(function(){e.hydrate()})},{timeout:this.idleTimeout});this.idle=function(){return cancelIdleCallback(t)}}if(this.whenVisible){var n=createObserver(!0===this.whenVisible?{}:this.whenVisible);if(!n)return void this.hydrate();this.$el.hydrate=this.hydrate,n.observe(this.$el.children[0]),this.visible=function(){n.unobserve(e.$el),delete e.$el.hydrate}}}}else this.hydrate()},beforeDestroy:function(){this.cleanup()},methods:{cleanup:function(){var e=this;["idle","interaction","visible"].forEach(function(t){t in e&&(e[t](),delete e[t])})},hydrate:function(){this.hydrated=!0,this.cleanup()}},render:function(e){var t=this.$el?this.$el.tagName:"div",n=this.$scopedSlots.default?this.$scopedSlots.default({hydrated:this.hydrated}):this.$slots.default[0],i=this.hydrated?n:e(t);return isBrowser&&(i.asyncFactory=this.hydrated?{resolved:!0}:{},i.isAsyncPlaceholder=!this.hydrated),i}};export default LazyHydrate; | ||
function asyncGeneratorStep(e,t,n,r,o,i,a){try{var s=e[i](a),c=s.value}catch(e){return void n(e)}s.done?t(c):Promise.resolve(c).then(r,o)}function _asyncToGenerator(e){return function(){var t=this,n=arguments;return new Promise(function(r,o){var i=e.apply(t,n);function a(e){asyncGeneratorStep(i,r,o,a,s,"next",e)}function s(e){asyncGeneratorStep(i,r,o,a,s,"throw",e)}a(void 0)})}}function _defineProperty(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}function _objectSpread(e){for(var t=1;t<arguments.length;t++){var n=null!=arguments[t]?arguments[t]:{},r=Object.keys(n);"function"==typeof Object.getOwnPropertySymbols&&(r=r.concat(Object.getOwnPropertySymbols(n).filter(function(e){return Object.getOwnPropertyDescriptor(n,e).enumerable}))),r.forEach(function(t){_defineProperty(e,t,n[t])})}return e}var observers=new Map;function createObserver(e){if("undefined"==typeof IntersectionObserver)return null;var t=JSON.stringify(e);if(observers.has(t))return observers.get(t);var n=new IntersectionObserver(function(e){e.forEach(function(e){(e.isIntersecting||e.intersectionRatio>0)&&e.target.hydrate&&e.target.hydrate()})},e);return observers.set(t,n),n}function loadingComponentFactory(e,t){return _objectSpread({render:function(t){var n=this.$el?this.$el.tagName:"div";return this.$el||e._resolve(),t(n)}},t)}function resolvableComponentFactory(e){var t,n=new Promise(function(e){t=e});return n._resolve=_asyncToGenerator(regeneratorRuntime.mark(function n(){return regeneratorRuntime.wrap(function(n){for(;;)switch(n.prev=n.next){case 0:if(n.t0=t,"function"!=typeof e){n.next=7;break}return n.next=4,e();case 4:n.t1=n.sent,n.next=8;break;case 7:n.t1=e;case 8:n.t2=n.t1,(0,n.t0)(n.t2);case 10:case"end":return n.stop()}},n)})),n}var isServer="undefined"==typeof window,isBrowser=!isServer;function hydrateWhenIdle(e,t){var n=t.ignoredProps;if(isServer)return e;var r=resolvableComponentFactory(e),o=loadingComponentFactory(r,{props:n,mounted:function(){if("requestIdleCallback"in window&&"requestAnimationFrame"in window){var e=requestIdleCallback(function(){requestAnimationFrame(r._resolve)},{timeout:this.idleTimeout});r.then(function(){return cancelIdleCallback(e)})}else r._resolve()}});return function(){return{component:r,delay:0,loading:o}}}function hydrateWhenVisible(e,t){var n=t.ignoredProps,r=t.observerOptions;if(isServer)return e;var o=resolvableComponentFactory(e),i=createObserver(r),a=loadingComponentFactory(o,{props:n,mounted:function(){var e=this;if(i){this.$el.hydrate=o._resolve;o.then(function(){return i.unobserve(e.$el)}),i.observe(this.$el)}else o._resolve()}});return function(){return{component:o,delay:0,loading:a}}}function hydrateSsrOnly(e){if(isServer)return e;var t=resolvableComponentFactory(e),n=loadingComponentFactory(t);return function(){return{component:t,delay:0,loading:n}}}function hydrateOnInteraction(e,t){var n=t.event,r=void 0===n?"focus":n,o=t.ignoredProps;if(isServer)return e;var i=resolvableComponentFactory(e),a=Array.isArray(r)?r:[r],s=loadingComponentFactory(i,{props:o,mounted:function(){var e=this;a.forEach(function(t){e.$el.addEventListener(t,i._resolve,{capture:!0,once:!0})})}});return function(){return{component:i,delay:0,loading:s}}}var LazyHydrate={props:{idleTimeout:{default:2e3,type:Number},onInteraction:{type:[Array,Boolean,String]},ssrOnly:{type:Boolean},triggerHydration:{default:!1,type:Boolean},whenIdle:{type:Boolean},whenVisible:{type:[Boolean,Object]}},data:function(){return{hydrated:isServer}},watch:{triggerHydration:{immediate:!0,handler:function(e){e&&this.hydrate()}}},computed:{interactionEvents:function(){return this.onInteraction?!0===this.onInteraction?["focus"]:Array.isArray(this.onInteraction)?this.onInteraction:[this.onInteraction]:[]}},mounted:function(){var e=this;if(0!==this.$el.childElementCount){if(!this.ssrOnly){if(this.interactionEvents.forEach(function(t){e.$el.addEventListener(t,e.hydrate,{capture:!0,once:!0})}),this.interactionEvents.length&&(this.interaction=function(){e.interactionEvents.forEach(function(t){return e.$el.removeEventListener(t,e.hydrate)})}),this.whenIdle){if(!("requestIdleCallback"in window&&"requestAnimationFrame"in window))return void this.hydrate();var t=requestIdleCallback(function(){requestAnimationFrame(function(){e.hydrate()})},{timeout:this.idleTimeout});this.idle=function(){return cancelIdleCallback(t)}}if(this.whenVisible){var n=createObserver(!0===this.whenVisible?{}:this.whenVisible);if(!n)return void this.hydrate();this.$el.hydrate=this.hydrate,n.observe(this.$el.children[0]),this.visible=function(){n.unobserve(e.$el),delete e.$el.hydrate}}}}else this.hydrate()},beforeDestroy:function(){this.cleanup()},methods:{cleanup:function(){var e=this;["idle","interaction","visible"].forEach(function(t){t in e&&(e[t](),delete e[t])})},hydrate:function(){this.hydrated=!0,this.cleanup()}},render:function(e){var t=this.$el?this.$el.tagName:"div",n=this.$scopedSlots.default?this.$scopedSlots.default({hydrated:this.hydrated}):this.$slots.default[0],r=this.hydrated?n:e(t);return isBrowser&&(r.asyncFactory=this.hydrated?{resolved:!0}:{},r.isAsyncPlaceholder=!this.hydrated),r}};export default LazyHydrate;export{hydrateWhenIdle,hydrateWhenVisible,hydrateSsrOnly,hydrateOnInteraction}; |
(function (global, factory) { | ||
typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() : | ||
typeof define === 'function' && define.amd ? define(factory) : | ||
(global = global || self, global['vue-lazy-hydration'] = factory()); | ||
}(this, function () { 'use strict'; | ||
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : | ||
typeof define === 'function' && define.amd ? define(['exports'], factory) : | ||
(global = global || self, factory(global['vue-lazy-hydration'] = {})); | ||
}(this, function (exports) { 'use strict'; | ||
var isServer = typeof window === "undefined"; | ||
var isBrowser = !isServer; | ||
function asyncGeneratorStep(gen, resolve, reject, _next, _throw, key, arg) { | ||
try { | ||
var info = gen[key](arg); | ||
var value = info.value; | ||
} catch (error) { | ||
reject(error); | ||
return; | ||
} | ||
if (info.done) { | ||
resolve(value); | ||
} else { | ||
Promise.resolve(value).then(_next, _throw); | ||
} | ||
} | ||
function _asyncToGenerator(fn) { | ||
return function () { | ||
var self = this, | ||
args = arguments; | ||
return new Promise(function (resolve, reject) { | ||
var gen = fn.apply(self, args); | ||
function _next(value) { | ||
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "next", value); | ||
} | ||
function _throw(err) { | ||
asyncGeneratorStep(gen, resolve, reject, _next, _throw, "throw", err); | ||
} | ||
_next(undefined); | ||
}); | ||
}; | ||
} | ||
function _defineProperty(obj, key, value) { | ||
if (key in obj) { | ||
Object.defineProperty(obj, key, { | ||
value: value, | ||
enumerable: true, | ||
configurable: true, | ||
writable: true | ||
}); | ||
} else { | ||
obj[key] = value; | ||
} | ||
return obj; | ||
} | ||
function _objectSpread(target) { | ||
for (var i = 1; i < arguments.length; i++) { | ||
var source = arguments[i] != null ? arguments[i] : {}; | ||
var ownKeys = Object.keys(source); | ||
if (typeof Object.getOwnPropertySymbols === 'function') { | ||
ownKeys = ownKeys.concat(Object.getOwnPropertySymbols(source).filter(function (sym) { | ||
return Object.getOwnPropertyDescriptor(source, sym).enumerable; | ||
})); | ||
} | ||
ownKeys.forEach(function (key) { | ||
_defineProperty(target, key, source[key]); | ||
}); | ||
} | ||
return target; | ||
} | ||
var observers = new Map(); | ||
function createObserver(options) { | ||
@@ -21,4 +88,4 @@ if (typeof IntersectionObserver === "undefined") return null; | ||
var isIntersecting = entry.isIntersecting || entry.intersectionRatio > 0; | ||
if (!isIntersecting || !entry.target.parentElement.hydrate) return; | ||
entry.target.parentElement.hydrate(); | ||
if (!isIntersecting || !entry.target.hydrate) return; | ||
entry.target.hydrate(); | ||
}); | ||
@@ -29,3 +96,178 @@ }, options); | ||
} | ||
function loadingComponentFactory(resolvableComponent, options) { | ||
return _objectSpread({ | ||
render: function render(h) { | ||
var tag = this.$el ? this.$el.tagName : "div"; // eslint-disable-next-line no-underscore-dangle | ||
if (!this.$el) resolvableComponent._resolve(); | ||
return h(tag); | ||
} | ||
}, options); | ||
} | ||
function resolvableComponentFactory(component) { | ||
var resolve; | ||
var promise = new Promise(function (newResolve) { | ||
resolve = newResolve; | ||
}); // eslint-disable-next-line no-underscore-dangle | ||
promise._resolve = | ||
/*#__PURE__*/ | ||
_asyncToGenerator( | ||
/*#__PURE__*/ | ||
regeneratorRuntime.mark(function _callee() { | ||
return regeneratorRuntime.wrap(function _callee$(_context) { | ||
while (1) { | ||
switch (_context.prev = _context.next) { | ||
case 0: | ||
_context.t0 = resolve; | ||
if (!(typeof component === "function")) { | ||
_context.next = 7; | ||
break; | ||
} | ||
_context.next = 4; | ||
return component(); | ||
case 4: | ||
_context.t1 = _context.sent; | ||
_context.next = 8; | ||
break; | ||
case 7: | ||
_context.t1 = component; | ||
case 8: | ||
_context.t2 = _context.t1; | ||
(0, _context.t0)(_context.t2); | ||
case 10: | ||
case "end": | ||
return _context.stop(); | ||
} | ||
} | ||
}, _callee); | ||
})); | ||
return promise; | ||
} | ||
var isServer = typeof window === "undefined"; | ||
var isBrowser = !isServer; | ||
function hydrateWhenIdle(component, _ref) { | ||
var ignoredProps = _ref.ignoredProps; | ||
if (isServer) return component; | ||
var resolvableComponent = resolvableComponentFactory(component); | ||
var loading = loadingComponentFactory(resolvableComponent, { | ||
props: ignoredProps, | ||
mounted: function mounted() { | ||
// If `requestIdleCallback()` or `requestAnimationFrame()` | ||
// is not supported, hydrate immediately. | ||
if (!("requestIdleCallback" in window) || !("requestAnimationFrame" in window)) { | ||
// eslint-disable-next-line no-underscore-dangle | ||
resolvableComponent._resolve(); | ||
return; | ||
} | ||
var id = requestIdleCallback(function () { | ||
// eslint-disable-next-line no-underscore-dangle | ||
requestAnimationFrame(resolvableComponent._resolve); | ||
}, { | ||
timeout: this.idleTimeout | ||
}); | ||
var cleanup = function cleanup() { | ||
return cancelIdleCallback(id); | ||
}; | ||
resolvableComponent.then(cleanup); | ||
} | ||
}); | ||
return function () { | ||
return { | ||
component: resolvableComponent, | ||
delay: 0, | ||
loading: loading | ||
}; | ||
}; | ||
} | ||
function hydrateWhenVisible(component, _ref2) { | ||
var ignoredProps = _ref2.ignoredProps, | ||
observerOptions = _ref2.observerOptions; | ||
if (isServer) return component; | ||
var resolvableComponent = resolvableComponentFactory(component); | ||
var observer = createObserver(observerOptions); | ||
var loading = loadingComponentFactory(resolvableComponent, { | ||
props: ignoredProps, | ||
mounted: function mounted() { | ||
var _this = this; | ||
// If Intersection Observer API is not supported, hydrate immediately. | ||
if (!observer) { | ||
// eslint-disable-next-line no-underscore-dangle | ||
resolvableComponent._resolve(); | ||
return; | ||
} // eslint-disable-next-line no-underscore-dangle | ||
this.$el.hydrate = resolvableComponent._resolve; | ||
var cleanup = function cleanup() { | ||
return observer.unobserve(_this.$el); | ||
}; | ||
resolvableComponent.then(cleanup); | ||
observer.observe(this.$el); | ||
} | ||
}); | ||
return function () { | ||
return { | ||
component: resolvableComponent, | ||
delay: 0, | ||
loading: loading | ||
}; | ||
}; | ||
} | ||
function hydrateSsrOnly(component) { | ||
if (isServer) return component; | ||
var resolvableComponent = resolvableComponentFactory(component); | ||
var loading = loadingComponentFactory(resolvableComponent); | ||
return function () { | ||
return { | ||
component: resolvableComponent, | ||
delay: 0, | ||
loading: loading | ||
}; | ||
}; | ||
} | ||
function hydrateOnInteraction(component, _ref3) { | ||
var _ref3$event = _ref3.event, | ||
event = _ref3$event === void 0 ? "focus" : _ref3$event, | ||
ignoredProps = _ref3.ignoredProps; | ||
if (isServer) return component; | ||
var resolvableComponent = resolvableComponentFactory(component); | ||
var events = Array.isArray(event) ? event : [event]; | ||
var loading = loadingComponentFactory(resolvableComponent, { | ||
props: ignoredProps, | ||
mounted: function mounted() { | ||
var _this2 = this; | ||
events.forEach(function (eventName) { | ||
// eslint-disable-next-line no-underscore-dangle | ||
_this2.$el.addEventListener(eventName, resolvableComponent._resolve, { | ||
capture: true, | ||
once: true | ||
}); | ||
}); | ||
} | ||
}); | ||
return function () { | ||
return { | ||
component: resolvableComponent, | ||
delay: 0, | ||
loading: loading | ||
}; | ||
}; | ||
} | ||
var LazyHydrate = { | ||
@@ -75,3 +317,3 @@ props: { | ||
mounted: function mounted() { | ||
var _this = this; | ||
var _this3 = this; | ||
@@ -86,3 +328,3 @@ if (this.$el.childElementCount === 0) { | ||
this.interactionEvents.forEach(function (eventName) { | ||
_this.$el.addEventListener(eventName, _this.hydrate, { | ||
_this3.$el.addEventListener(eventName, _this3.hydrate, { | ||
capture: true, | ||
@@ -95,4 +337,4 @@ once: true | ||
this.interaction = function () { | ||
_this.interactionEvents.forEach(function (eventName) { | ||
return _this.$el.removeEventListener(eventName, _this.hydrate); | ||
_this3.interactionEvents.forEach(function (eventName) { | ||
return _this3.$el.removeEventListener(eventName, _this3.hydrate); | ||
}); | ||
@@ -112,3 +354,3 @@ }; | ||
requestAnimationFrame(function () { | ||
_this.hydrate(); | ||
_this3.hydrate(); | ||
}); | ||
@@ -137,4 +379,4 @@ }, { | ||
this.visible = function () { | ||
observer.unobserve(_this.$el); | ||
delete _this.$el.hydrate; | ||
observer.unobserve(_this3.$el); | ||
delete _this3.$el.hydrate; | ||
}; | ||
@@ -148,10 +390,10 @@ } | ||
cleanup: function cleanup() { | ||
var _this2 = this; | ||
var _this4 = this; | ||
var handlers = ["idle", "interaction", "visible"]; | ||
handlers.forEach(function (handler) { | ||
if (handler in _this2) { | ||
_this2[handler](); | ||
if (handler in _this4) { | ||
_this4[handler](); | ||
delete _this2[handler]; | ||
delete _this4[handler]; | ||
} | ||
@@ -184,4 +426,10 @@ }); | ||
return LazyHydrate; | ||
exports.hydrateWhenIdle = hydrateWhenIdle; | ||
exports.hydrateWhenVisible = hydrateWhenVisible; | ||
exports.hydrateSsrOnly = hydrateSsrOnly; | ||
exports.hydrateOnInteraction = hydrateOnInteraction; | ||
exports.default = LazyHydrate; | ||
Object.defineProperty(exports, '__esModule', { value: true }); | ||
})); |
@@ -1,1 +0,1 @@ | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t():"function"==typeof define&&define.amd?define(t):(e=e||self)["vue-lazy-hydration"]=t()}(this,function(){"use strict";var e="undefined"==typeof window,t=!e,n=new Map;return{props:{idleTimeout:{default:2e3,type:Number},onInteraction:{type:[Array,Boolean,String]},ssrOnly:{type:Boolean},triggerHydration:{default:!1,type:Boolean},whenIdle:{type:Boolean},whenVisible:{type:[Boolean,Object]}},data:function(){return{hydrated:e}},watch:{triggerHydration:{immediate:!0,handler:function(e){e&&this.hydrate()}}},computed:{interactionEvents:function(){return this.onInteraction?!0===this.onInteraction?["focus"]:Array.isArray(this.onInteraction)?this.onInteraction:[this.onInteraction]:[]}},mounted:function(){var e=this;if(0!==this.$el.childElementCount){if(!this.ssrOnly){if(this.interactionEvents.forEach(function(t){e.$el.addEventListener(t,e.hydrate,{capture:!0,once:!0})}),this.interactionEvents.length&&(this.interaction=function(){e.interactionEvents.forEach(function(t){return e.$el.removeEventListener(t,e.hydrate)})}),this.whenIdle){if(!("requestIdleCallback"in window&&"requestAnimationFrame"in window))return void this.hydrate();var t=requestIdleCallback(function(){requestAnimationFrame(function(){e.hydrate()})},{timeout:this.idleTimeout});this.idle=function(){return cancelIdleCallback(t)}}if(this.whenVisible){var i=function(e){if("undefined"==typeof IntersectionObserver)return null;var t=JSON.stringify(e);if(n.has(t))return n.get(t);var i=new IntersectionObserver(function(e){e.forEach(function(e){(e.isIntersecting||e.intersectionRatio>0)&&e.target.parentElement.hydrate&&e.target.parentElement.hydrate()})},e);return n.set(t,i),i}(!0===this.whenVisible?{}:this.whenVisible);if(!i)return void this.hydrate();this.$el.hydrate=this.hydrate,i.observe(this.$el.children[0]),this.visible=function(){i.unobserve(e.$el),delete e.$el.hydrate}}}}else this.hydrate()},beforeDestroy:function(){this.cleanup()},methods:{cleanup:function(){var e=this;["idle","interaction","visible"].forEach(function(t){t in e&&(e[t](),delete e[t])})},hydrate:function(){this.hydrated=!0,this.cleanup()}},render:function(e){var n=this.$el?this.$el.tagName:"div",i=this.$scopedSlots.default?this.$scopedSlots.default({hydrated:this.hydrated}):this.$slots.default[0],r=this.hydrated?i:e(n);return t&&(r.asyncFactory=this.hydrated?{resolved:!0}:{},r.isAsyncPlaceholder=!this.hydrated),r}}}); | ||
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports):"function"==typeof define&&define.amd?define(["exports"],t):t((e=e||self)["vue-lazy-hydration"]={})}(this,function(e){"use strict";function t(e,t,n,r,i,o,a){try{var s=e[o](a),u=s.value}catch(e){return void n(e)}s.done?t(u):Promise.resolve(u).then(r,i)}function n(e,t,n){return t in e?Object.defineProperty(e,t,{value:n,enumerable:!0,configurable:!0,writable:!0}):e[t]=n,e}var r=new Map;function i(e){if("undefined"==typeof IntersectionObserver)return null;var t=JSON.stringify(e);if(r.has(t))return r.get(t);var n=new IntersectionObserver(function(e){e.forEach(function(e){(e.isIntersecting||e.intersectionRatio>0)&&e.target.hydrate&&e.target.hydrate()})},e);return r.set(t,n),n}function o(e,t){return function(e){for(var t=1;t<arguments.length;t++){var r=null!=arguments[t]?arguments[t]:{},i=Object.keys(r);"function"==typeof Object.getOwnPropertySymbols&&(i=i.concat(Object.getOwnPropertySymbols(r).filter(function(e){return Object.getOwnPropertyDescriptor(r,e).enumerable}))),i.forEach(function(t){n(e,t,r[t])})}return e}({render:function(t){var n=this.$el?this.$el.tagName:"div";return this.$el||e._resolve(),t(n)}},t)}function a(e){var n,r=new Promise(function(e){n=e});return r._resolve=function(e){return function(){var n=this,r=arguments;return new Promise(function(i,o){var a=e.apply(n,r);function s(e){t(a,i,o,s,u,"next",e)}function u(e){t(a,i,o,s,u,"throw",e)}s(void 0)})}}(regeneratorRuntime.mark(function t(){return regeneratorRuntime.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:if(t.t0=n,"function"!=typeof e){t.next=7;break}return t.next=4,e();case 4:t.t1=t.sent,t.next=8;break;case 7:t.t1=e;case 8:t.t2=t.t1,(0,t.t0)(t.t2);case 10:case"end":return t.stop()}},t)})),r}var s="undefined"==typeof window,u=!s;var c={props:{idleTimeout:{default:2e3,type:Number},onInteraction:{type:[Array,Boolean,String]},ssrOnly:{type:Boolean},triggerHydration:{default:!1,type:Boolean},whenIdle:{type:Boolean},whenVisible:{type:[Boolean,Object]}},data:function(){return{hydrated:s}},watch:{triggerHydration:{immediate:!0,handler:function(e){e&&this.hydrate()}}},computed:{interactionEvents:function(){return this.onInteraction?!0===this.onInteraction?["focus"]:Array.isArray(this.onInteraction)?this.onInteraction:[this.onInteraction]:[]}},mounted:function(){var e=this;if(0!==this.$el.childElementCount){if(!this.ssrOnly){if(this.interactionEvents.forEach(function(t){e.$el.addEventListener(t,e.hydrate,{capture:!0,once:!0})}),this.interactionEvents.length&&(this.interaction=function(){e.interactionEvents.forEach(function(t){return e.$el.removeEventListener(t,e.hydrate)})}),this.whenIdle){if(!("requestIdleCallback"in window&&"requestAnimationFrame"in window))return void this.hydrate();var t=requestIdleCallback(function(){requestAnimationFrame(function(){e.hydrate()})},{timeout:this.idleTimeout});this.idle=function(){return cancelIdleCallback(t)}}if(this.whenVisible){var n=i(!0===this.whenVisible?{}:this.whenVisible);if(!n)return void this.hydrate();this.$el.hydrate=this.hydrate,n.observe(this.$el.children[0]),this.visible=function(){n.unobserve(e.$el),delete e.$el.hydrate}}}}else this.hydrate()},beforeDestroy:function(){this.cleanup()},methods:{cleanup:function(){var e=this;["idle","interaction","visible"].forEach(function(t){t in e&&(e[t](),delete e[t])})},hydrate:function(){this.hydrated=!0,this.cleanup()}},render:function(e){var t=this.$el?this.$el.tagName:"div",n=this.$scopedSlots.default?this.$scopedSlots.default({hydrated:this.hydrated}):this.$slots.default[0],r=this.hydrated?n:e(t);return u&&(r.asyncFactory=this.hydrated?{resolved:!0}:{},r.isAsyncPlaceholder=!this.hydrated),r}};e.hydrateWhenIdle=function(e,t){var n=t.ignoredProps;if(s)return e;var r=a(e),i=o(r,{props:n,mounted:function(){if("requestIdleCallback"in window&&"requestAnimationFrame"in window){var e=requestIdleCallback(function(){requestAnimationFrame(r._resolve)},{timeout:this.idleTimeout});r.then(function(){return cancelIdleCallback(e)})}else r._resolve()}});return function(){return{component:r,delay:0,loading:i}}},e.hydrateWhenVisible=function(e,t){var n=t.ignoredProps,r=t.observerOptions;if(s)return e;var u=a(e),c=i(r),l=o(u,{props:n,mounted:function(){var e=this;c?(this.$el.hydrate=u._resolve,u.then(function(){return c.unobserve(e.$el)}),c.observe(this.$el)):u._resolve()}});return function(){return{component:u,delay:0,loading:l}}},e.hydrateSsrOnly=function(e){if(s)return e;var t=a(e),n=o(t);return function(){return{component:t,delay:0,loading:n}}},e.hydrateOnInteraction=function(e,t){var n=t.event,r=void 0===n?"focus":n,i=t.ignoredProps;if(s)return e;var u=a(e),c=Array.isArray(r)?r:[r],l=o(u,{props:i,mounted:function(){var e=this;c.forEach(function(t){e.$el.addEventListener(t,u._resolve,{capture:!0,once:!0})})}});return function(){return{component:u,delay:0,loading:l}}},e.default=c,Object.defineProperty(e,"__esModule",{value:!0})}); |
{ | ||
"name": "vue-lazy-hydration", | ||
"version": "1.0.0-beta.4", | ||
"version": "1.0.0-beta.5", | ||
"description": "Lazy hydration of server-side rendered Vue.js components", | ||
@@ -27,9 +27,9 @@ "keywords": [ | ||
"@avalanche/eslint-config": "^3.0.0", | ||
"@babel/core": "^7.2.2", | ||
"@babel/preset-env": "^7.3.1", | ||
"eslint": "^5.13.0", | ||
"eslint-plugin-compat": "^2.6.3", | ||
"@babel/core": "^7.3.4", | ||
"@babel/preset-env": "^7.3.4", | ||
"eslint": "^5.14.1", | ||
"eslint-plugin-compat": "^2.7.0", | ||
"eslint-plugin-import": "^2.16.0", | ||
"eslint-plugin-markdown": "^1.0.0", | ||
"rollup": "^1.1.2", | ||
"rollup": "^1.3.3", | ||
"rollup-plugin-babel": "^4.3.2", | ||
@@ -36,0 +36,0 @@ "uglify-es": "^3.3.9" |
@@ -34,3 +34,3 @@ # vue-lazy-hydration | ||
### Basic example | ||
## Basic example | ||
@@ -90,5 +90,5 @@ In the example below you can see the four hydration modes in action. | ||
### Advanced | ||
## Advanced | ||
#### Prevent JavaScript bundle loading | ||
### Prevent JavaScript bundle loading | ||
@@ -105,2 +105,12 @@ ```html | ||
</LazyHydrate> | ||
<!-- Or using new Vue.js 2.6.x v-slot syntax --> | ||
<LazyHydrate | ||
v-slot="{ hydrated }" | ||
on-interaction | ||
> | ||
<CommentForm | ||
v-if="hydrated" | ||
:article-id="article.id" | ||
/> | ||
</LazyHydrate> | ||
</div> | ||
@@ -123,3 +133,3 @@ </template> | ||
#### Manually trigger hydration | ||
### Manually trigger hydration | ||
@@ -158,3 +168,3 @@ Sometimes you might want to prevent a component from loading initially but you want to activate it on demand if a certain action is triggered. You can do this by manually triggering the component to hydrate like you can see in the following example. | ||
#### Multiple root nodes | ||
### Multiple root nodes | ||
@@ -178,3 +188,3 @@ Because of how this package works, it is not possible to nest multiple root nodes inside of a single `<LazyHydrate>`. But you can wrap multiple components with a `<div>`. | ||
#### Intersection Obersver options | ||
### Intersection Obersver options | ||
@@ -195,2 +205,55 @@ Internally the [Intersection Observer API](https://developer.mozilla.org/en-US/docs/Web/API/IntersectionObserver/IntersectionObserver) is used to determine if a component is visible or not. You can provide Intersection Observer options to the `when-visible` property to configure the Intersection Observer. | ||
## Import Wrappers | ||
> **Attention:** because of [a bug in Vue.js <= v2.6.7](https://github.com/vuejs/vue/pull/9572) Import Wrappers require that you have at least version **v2.6.8** of Vue.js installed otherwise they will not work correctly in certain situations (especially in combination with Vue Router). | ||
Additionally to the `<LazyHydrate>` wrapper component you can also use Import Wrappers to lazy load and hydrate certain components. | ||
```html | ||
<template> | ||
<div class="ArticlePage"> | ||
<ImageSlider/> | ||
<ArticleContent :content="article.content"/> | ||
<AdSlider/> | ||
<CommentForm :article-id="article.id"/> | ||
</div> | ||
</template> | ||
<script> | ||
import { | ||
hydrateOnInteraction, | ||
hydrateSsrOnly, | ||
hydrateWhenIdle, | ||
hydrateWhenVisible, | ||
} from 'vue-lazy-hydration'; | ||
export default { | ||
components: { | ||
AdSlider: hydrateWhenVisible( | ||
() => import('./AdSlider.vue'), | ||
// Optional. | ||
{ observerOptions: { rootMargin: '100px' } }, | ||
), | ||
ArticleContent: hydrateSsrOnly( | ||
() => import('./ArticleContent.vue'), | ||
{ ignoredProps: ['content'] }, | ||
), | ||
CommentForm: hydrateOnInteraction( | ||
() => import('./CommentForm.vue'), | ||
// `focus` is the default event. | ||
{ event: 'focus', ignoredProps: ['articleId'] }, | ||
), | ||
ImageSlider: hydrateWhenIdle(() => import('./ImageSlider.vue')), | ||
}, | ||
// ... | ||
}; | ||
</script> | ||
``` | ||
### Caveats | ||
1. Properties passed to a wrapped component are rendered as an HTML attribute on the root element. | ||
E.g. `<ArticleContent :content="article.content"/>` would render to `<div class="ArticleContent" content="Lorem ipsum dolor ...">Lorem ipsum dolor ...</div>` as long as you don't provide `content` as an ignored property the way you can see in the example above. | ||
2. When using `hydrateWhenVisible` and `hydrateOnInteraction` all instances of a certain component are immediately hydrated as soon as one of the instances becomes visible or is interacted with. | ||
## Benchmarks | ||
@@ -197,0 +260,0 @@ |
@@ -0,28 +1,111 @@ | ||
import { | ||
createObserver, | ||
loadingComponentFactory, | ||
resolvableComponentFactory, | ||
} from './utils'; | ||
const isServer = typeof window === `undefined`; | ||
const isBrowser = !isServer; | ||
const observers = new Map(); | ||
export function hydrateWhenIdle(component, { ignoredProps }) { | ||
if (isServer) return component; | ||
function createObserver(options) { | ||
if (typeof IntersectionObserver === `undefined`) return null; | ||
const resolvableComponent = resolvableComponentFactory(component); | ||
const loading = loadingComponentFactory(resolvableComponent, { | ||
props: ignoredProps, | ||
mounted() { | ||
// If `requestIdleCallback()` or `requestAnimationFrame()` | ||
// is not supported, hydrate immediately. | ||
if (!(`requestIdleCallback` in window) || !(`requestAnimationFrame` in window)) { | ||
// eslint-disable-next-line no-underscore-dangle | ||
resolvableComponent._resolve(); | ||
return; | ||
} | ||
const optionKey = JSON.stringify(options); | ||
if (observers.has(optionKey)) return observers.get(optionKey); | ||
const id = requestIdleCallback(() => { | ||
// eslint-disable-next-line no-underscore-dangle | ||
requestAnimationFrame(resolvableComponent._resolve); | ||
}, { timeout: this.idleTimeout }); | ||
const cleanup = () => cancelIdleCallback(id); | ||
resolvableComponent.then(cleanup); | ||
}, | ||
}); | ||
const observer = new IntersectionObserver((entries) => { | ||
entries.forEach((entry) => { | ||
// Use `intersectionRatio` because of Edge 15's | ||
// lack of support for `isIntersecting`. | ||
// See: https://github.com/w3c/IntersectionObserver/issues/211 | ||
const isIntersecting = entry.isIntersecting || entry.intersectionRatio > 0; | ||
if (!isIntersecting || !entry.target.parentElement.hydrate) return; | ||
return () => ({ | ||
component: resolvableComponent, | ||
delay: 0, | ||
loading, | ||
}); | ||
} | ||
entry.target.parentElement.hydrate(); | ||
}); | ||
}, options); | ||
observers.set(optionKey, observer); | ||
export function hydrateWhenVisible(component, { ignoredProps, observerOptions }) { | ||
if (isServer) return component; | ||
return observer; | ||
const resolvableComponent = resolvableComponentFactory(component); | ||
const observer = createObserver(observerOptions); | ||
const loading = loadingComponentFactory(resolvableComponent, { | ||
props: ignoredProps, | ||
mounted() { | ||
// If Intersection Observer API is not supported, hydrate immediately. | ||
if (!observer) { | ||
// eslint-disable-next-line no-underscore-dangle | ||
resolvableComponent._resolve(); | ||
return; | ||
} | ||
// eslint-disable-next-line no-underscore-dangle | ||
this.$el.hydrate = resolvableComponent._resolve; | ||
const cleanup = () => observer.unobserve(this.$el); | ||
resolvableComponent.then(cleanup); | ||
observer.observe(this.$el); | ||
}, | ||
}); | ||
return () => ({ | ||
component: resolvableComponent, | ||
delay: 0, | ||
loading, | ||
}); | ||
} | ||
export function hydrateSsrOnly(component) { | ||
if (isServer) return component; | ||
const resolvableComponent = resolvableComponentFactory(component); | ||
const loading = loadingComponentFactory(resolvableComponent); | ||
return () => ({ | ||
component: resolvableComponent, | ||
delay: 0, | ||
loading, | ||
}); | ||
} | ||
export function hydrateOnInteraction(component, { event = `focus`, ignoredProps }) { | ||
if (isServer) return component; | ||
const resolvableComponent = resolvableComponentFactory(component); | ||
const events = Array.isArray(event) ? event : [event]; | ||
const loading = loadingComponentFactory(resolvableComponent, { | ||
props: ignoredProps, | ||
mounted() { | ||
events.forEach((eventName) => { | ||
// eslint-disable-next-line no-underscore-dangle | ||
this.$el.addEventListener(eventName, resolvableComponent._resolve, { | ||
capture: true, | ||
once: true, | ||
}); | ||
}); | ||
}, | ||
}); | ||
return () => ({ | ||
component: resolvableComponent, | ||
delay: 0, | ||
loading, | ||
}); | ||
} | ||
export default { | ||
@@ -29,0 +112,0 @@ props: { |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
1311
288
69148