You cannot select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
	
	
		
			345 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
		
		
			
		
	
	
			345 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			JavaScript
		
	
| 
											9 months ago
										 | "use client"; | ||
|  | 
 | ||
|  | "use strict"; | ||
|  | Object.defineProperty(exports, "__esModule", { | ||
|  |     value: true | ||
|  | }); | ||
|  | 0 && (module.exports = { | ||
|  |     handleClientScriptLoad: null, | ||
|  |     initScriptLoader: null, | ||
|  |     default: null | ||
|  | }); | ||
|  | function _export(target, all) { | ||
|  |     for(var name in all)Object.defineProperty(target, name, { | ||
|  |         enumerable: true, | ||
|  |         get: all[name] | ||
|  |     }); | ||
|  | } | ||
|  | _export(exports, { | ||
|  |     handleClientScriptLoad: function() { | ||
|  |         return handleClientScriptLoad; | ||
|  |     }, | ||
|  |     initScriptLoader: function() { | ||
|  |         return initScriptLoader; | ||
|  |     }, | ||
|  |     default: function() { | ||
|  |         return _default; | ||
|  |     } | ||
|  | }); | ||
|  | const _interop_require_default = require("@swc/helpers/_/_interop_require_default"); | ||
|  | const _interop_require_wildcard = require("@swc/helpers/_/_interop_require_wildcard"); | ||
|  | const _jsxruntime = require("react/jsx-runtime"); | ||
|  | const _reactdom = /*#__PURE__*/ _interop_require_default._(require("react-dom")); | ||
|  | const _react = /*#__PURE__*/ _interop_require_wildcard._(require("react")); | ||
|  | const _headmanagercontextsharedruntime = require("../shared/lib/head-manager-context.shared-runtime"); | ||
|  | const _headmanager = require("./head-manager"); | ||
|  | const _requestidlecallback = require("./request-idle-callback"); | ||
|  | const ScriptCache = new Map(); | ||
|  | const LoadCache = new Set(); | ||
|  | const ignoreProps = [ | ||
|  |     "onLoad", | ||
|  |     "onReady", | ||
|  |     "dangerouslySetInnerHTML", | ||
|  |     "children", | ||
|  |     "onError", | ||
|  |     "strategy", | ||
|  |     "stylesheets" | ||
|  | ]; | ||
|  | const insertStylesheets = (stylesheets)=>{ | ||
|  |     // Case 1: Styles for afterInteractive/lazyOnload with appDir injected via handleClientScriptLoad
 | ||
|  |     //
 | ||
|  |     // Using ReactDOM.preinit to feature detect appDir and inject styles
 | ||
|  |     // Stylesheets might have already been loaded if initialized with Script component
 | ||
|  |     // Re-inject styles here to handle scripts loaded via handleClientScriptLoad
 | ||
|  |     // ReactDOM.preinit handles dedup and ensures the styles are loaded only once
 | ||
|  |     if (_reactdom.default.preinit) { | ||
|  |         stylesheets.forEach((stylesheet)=>{ | ||
|  |             _reactdom.default.preinit(stylesheet, { | ||
|  |                 as: "style" | ||
|  |             }); | ||
|  |         }); | ||
|  |         return; | ||
|  |     } | ||
|  |     // Case 2: Styles for afterInteractive/lazyOnload with pages injected via handleClientScriptLoad
 | ||
|  |     //
 | ||
|  |     // We use this function to load styles when appdir is not detected
 | ||
|  |     // TODO: Use React float APIs to load styles once available for pages dir
 | ||
|  |     if (typeof window !== "undefined") { | ||
|  |         let head = document.head; | ||
|  |         stylesheets.forEach((stylesheet)=>{ | ||
|  |             let link = document.createElement("link"); | ||
|  |             link.type = "text/css"; | ||
|  |             link.rel = "stylesheet"; | ||
|  |             link.href = stylesheet; | ||
|  |             head.appendChild(link); | ||
|  |         }); | ||
|  |     } | ||
|  | }; | ||
|  | const loadScript = (props)=>{ | ||
|  |     const { src, id, onLoad = ()=>{}, onReady = null, dangerouslySetInnerHTML, children = "", strategy = "afterInteractive", onError, stylesheets } = props; | ||
|  |     const cacheKey = id || src; | ||
|  |     // Script has already loaded
 | ||
|  |     if (cacheKey && LoadCache.has(cacheKey)) { | ||
|  |         return; | ||
|  |     } | ||
|  |     // Contents of this script are already loading/loaded
 | ||
|  |     if (ScriptCache.has(src)) { | ||
|  |         LoadCache.add(cacheKey); | ||
|  |         // It is possible that multiple `next/script` components all have same "src", but has different "onLoad"
 | ||
|  |         // This is to make sure the same remote script will only load once, but "onLoad" are executed in order
 | ||
|  |         ScriptCache.get(src).then(onLoad, onError); | ||
|  |         return; | ||
|  |     } | ||
|  |     /** Execute after the script first loaded */ const afterLoad = ()=>{ | ||
|  |         // Run onReady for the first time after load event
 | ||
|  |         if (onReady) { | ||
|  |             onReady(); | ||
|  |         } | ||
|  |         // add cacheKey to LoadCache when load successfully
 | ||
|  |         LoadCache.add(cacheKey); | ||
|  |     }; | ||
|  |     const el = document.createElement("script"); | ||
|  |     const loadPromise = new Promise((resolve, reject)=>{ | ||
|  |         el.addEventListener("load", function(e) { | ||
|  |             resolve(); | ||
|  |             if (onLoad) { | ||
|  |                 onLoad.call(this, e); | ||
|  |             } | ||
|  |             afterLoad(); | ||
|  |         }); | ||
|  |         el.addEventListener("error", function(e) { | ||
|  |             reject(e); | ||
|  |         }); | ||
|  |     }).catch(function(e) { | ||
|  |         if (onError) { | ||
|  |             onError(e); | ||
|  |         } | ||
|  |     }); | ||
|  |     if (dangerouslySetInnerHTML) { | ||
|  |         // Casting since lib.dom.d.ts doesn't have TrustedHTML yet.
 | ||
|  |         el.innerHTML = dangerouslySetInnerHTML.__html || ""; | ||
|  |         afterLoad(); | ||
|  |     } else if (children) { | ||
|  |         el.textContent = typeof children === "string" ? children : Array.isArray(children) ? children.join("") : ""; | ||
|  |         afterLoad(); | ||
|  |     } else if (src) { | ||
|  |         el.src = src; | ||
|  |         // do not add cacheKey into LoadCache for remote script here
 | ||
|  |         // cacheKey will be added to LoadCache when it is actually loaded (see loadPromise above)
 | ||
|  |         ScriptCache.set(src, loadPromise); | ||
|  |     } | ||
|  |     for (const [k, value] of Object.entries(props)){ | ||
|  |         if (value === undefined || ignoreProps.includes(k)) { | ||
|  |             continue; | ||
|  |         } | ||
|  |         const attr = _headmanager.DOMAttributeNames[k] || k.toLowerCase(); | ||
|  |         el.setAttribute(attr, value); | ||
|  |     } | ||
|  |     if (strategy === "worker") { | ||
|  |         el.setAttribute("type", "text/partytown"); | ||
|  |     } | ||
|  |     el.setAttribute("data-nscript", strategy); | ||
|  |     // Load styles associated with this script
 | ||
|  |     if (stylesheets) { | ||
|  |         insertStylesheets(stylesheets); | ||
|  |     } | ||
|  |     document.body.appendChild(el); | ||
|  | }; | ||
|  | function handleClientScriptLoad(props) { | ||
|  |     const { strategy = "afterInteractive" } = props; | ||
|  |     if (strategy === "lazyOnload") { | ||
|  |         window.addEventListener("load", ()=>{ | ||
|  |             (0, _requestidlecallback.requestIdleCallback)(()=>loadScript(props)); | ||
|  |         }); | ||
|  |     } else { | ||
|  |         loadScript(props); | ||
|  |     } | ||
|  | } | ||
|  | function loadLazyScript(props) { | ||
|  |     if (document.readyState === "complete") { | ||
|  |         (0, _requestidlecallback.requestIdleCallback)(()=>loadScript(props)); | ||
|  |     } else { | ||
|  |         window.addEventListener("load", ()=>{ | ||
|  |             (0, _requestidlecallback.requestIdleCallback)(()=>loadScript(props)); | ||
|  |         }); | ||
|  |     } | ||
|  | } | ||
|  | function addBeforeInteractiveToCache() { | ||
|  |     const scripts = [ | ||
|  |         ...document.querySelectorAll('[data-nscript="beforeInteractive"]'), | ||
|  |         ...document.querySelectorAll('[data-nscript="beforePageRender"]') | ||
|  |     ]; | ||
|  |     scripts.forEach((script)=>{ | ||
|  |         const cacheKey = script.id || script.getAttribute("src"); | ||
|  |         LoadCache.add(cacheKey); | ||
|  |     }); | ||
|  | } | ||
|  | function initScriptLoader(scriptLoaderItems) { | ||
|  |     scriptLoaderItems.forEach(handleClientScriptLoad); | ||
|  |     addBeforeInteractiveToCache(); | ||
|  | } | ||
|  | function Script(props) { | ||
|  |     const { id, src = "", onLoad = ()=>{}, onReady = null, strategy = "afterInteractive", onError, stylesheets, ...restProps } = props; | ||
|  |     // Context is available only during SSR
 | ||
|  |     const { updateScripts, scripts, getIsSsr, appDir, nonce } = (0, _react.useContext)(_headmanagercontextsharedruntime.HeadManagerContext); | ||
|  |     /** | ||
|  |    * - First mount: | ||
|  |    *   1. The useEffect for onReady executes | ||
|  |    *   2. hasOnReadyEffectCalled.current is false, but the script hasn't loaded yet (not in LoadCache) | ||
|  |    *      onReady is skipped, set hasOnReadyEffectCalled.current to true | ||
|  |    *   3. The useEffect for loadScript executes | ||
|  |    *   4. hasLoadScriptEffectCalled.current is false, loadScript executes | ||
|  |    *      Once the script is loaded, the onLoad and onReady will be called by then | ||
|  |    *   [If strict mode is enabled / is wrapped in <OffScreen /> component] | ||
|  |    *   5. The useEffect for onReady executes again | ||
|  |    *   6. hasOnReadyEffectCalled.current is true, so entire effect is skipped | ||
|  |    *   7. The useEffect for loadScript executes again | ||
|  |    *   8. hasLoadScriptEffectCalled.current is true, so entire effect is skipped | ||
|  |    * | ||
|  |    * - Second mount: | ||
|  |    *   1. The useEffect for onReady executes | ||
|  |    *   2. hasOnReadyEffectCalled.current is false, but the script has already loaded (found in LoadCache) | ||
|  |    *      onReady is called, set hasOnReadyEffectCalled.current to true | ||
|  |    *   3. The useEffect for loadScript executes | ||
|  |    *   4. The script is already loaded, loadScript bails out | ||
|  |    *   [If strict mode is enabled / is wrapped in <OffScreen /> component] | ||
|  |    *   5. The useEffect for onReady executes again | ||
|  |    *   6. hasOnReadyEffectCalled.current is true, so entire effect is skipped | ||
|  |    *   7. The useEffect for loadScript executes again | ||
|  |    *   8. hasLoadScriptEffectCalled.current is true, so entire effect is skipped | ||
|  |    */ const hasOnReadyEffectCalled = (0, _react.useRef)(false); | ||
|  |     (0, _react.useEffect)(()=>{ | ||
|  |         const cacheKey = id || src; | ||
|  |         if (!hasOnReadyEffectCalled.current) { | ||
|  |             // Run onReady if script has loaded before but component is re-mounted
 | ||
|  |             if (onReady && cacheKey && LoadCache.has(cacheKey)) { | ||
|  |                 onReady(); | ||
|  |             } | ||
|  |             hasOnReadyEffectCalled.current = true; | ||
|  |         } | ||
|  |     }, [ | ||
|  |         onReady, | ||
|  |         id, | ||
|  |         src | ||
|  |     ]); | ||
|  |     const hasLoadScriptEffectCalled = (0, _react.useRef)(false); | ||
|  |     (0, _react.useEffect)(()=>{ | ||
|  |         if (!hasLoadScriptEffectCalled.current) { | ||
|  |             if (strategy === "afterInteractive") { | ||
|  |                 loadScript(props); | ||
|  |             } else if (strategy === "lazyOnload") { | ||
|  |                 loadLazyScript(props); | ||
|  |             } | ||
|  |             hasLoadScriptEffectCalled.current = true; | ||
|  |         } | ||
|  |     }, [ | ||
|  |         props, | ||
|  |         strategy | ||
|  |     ]); | ||
|  |     if (strategy === "beforeInteractive" || strategy === "worker") { | ||
|  |         if (updateScripts) { | ||
|  |             scripts[strategy] = (scripts[strategy] || []).concat([ | ||
|  |                 { | ||
|  |                     id, | ||
|  |                     src, | ||
|  |                     onLoad, | ||
|  |                     onReady, | ||
|  |                     onError, | ||
|  |                     ...restProps | ||
|  |                 } | ||
|  |             ]); | ||
|  |             updateScripts(scripts); | ||
|  |         } else if (getIsSsr && getIsSsr()) { | ||
|  |             // Script has already loaded during SSR
 | ||
|  |             LoadCache.add(id || src); | ||
|  |         } else if (getIsSsr && !getIsSsr()) { | ||
|  |             loadScript(props); | ||
|  |         } | ||
|  |     } | ||
|  |     // For the app directory, we need React Float to preload these scripts.
 | ||
|  |     if (appDir) { | ||
|  |         // Injecting stylesheets here handles beforeInteractive and worker scripts correctly
 | ||
|  |         // For other strategies injecting here ensures correct stylesheet order
 | ||
|  |         // ReactDOM.preinit handles loading the styles in the correct order,
 | ||
|  |         // also ensures the stylesheet is loaded only once and in a consistent manner
 | ||
|  |         //
 | ||
|  |         // Case 1: Styles for beforeInteractive/worker with appDir - handled here
 | ||
|  |         // Case 2: Styles for beforeInteractive/worker with pages dir - Not handled yet
 | ||
|  |         // Case 3: Styles for afterInteractive/lazyOnload with appDir - handled here
 | ||
|  |         // Case 4: Styles for afterInteractive/lazyOnload with pages dir - handled in insertStylesheets function
 | ||
|  |         if (stylesheets) { | ||
|  |             stylesheets.forEach((styleSrc)=>{ | ||
|  |                 _reactdom.default.preinit(styleSrc, { | ||
|  |                     as: "style" | ||
|  |                 }); | ||
|  |             }); | ||
|  |         } | ||
|  |         // Before interactive scripts need to be loaded by Next.js' runtime instead
 | ||
|  |         // of native <script> tags, because they no longer have `defer`.
 | ||
|  |         if (strategy === "beforeInteractive") { | ||
|  |             if (!src) { | ||
|  |                 // For inlined scripts, we put the content in `children`.
 | ||
|  |                 if (restProps.dangerouslySetInnerHTML) { | ||
|  |                     // Casting since lib.dom.d.ts doesn't have TrustedHTML yet.
 | ||
|  |                     restProps.children = restProps.dangerouslySetInnerHTML.__html; | ||
|  |                     delete restProps.dangerouslySetInnerHTML; | ||
|  |                 } | ||
|  |                 return /*#__PURE__*/ (0, _jsxruntime.jsx)("script", { | ||
|  |                     nonce: nonce, | ||
|  |                     dangerouslySetInnerHTML: { | ||
|  |                         __html: "(self.__next_s=self.__next_s||[]).push(" + JSON.stringify([ | ||
|  |                             0, | ||
|  |                             { | ||
|  |                                 ...restProps, | ||
|  |                                 id | ||
|  |                             } | ||
|  |                         ]) + ")" | ||
|  |                     } | ||
|  |                 }); | ||
|  |             } else { | ||
|  |                 // @ts-ignore
 | ||
|  |                 _reactdom.default.preload(src, restProps.integrity ? { | ||
|  |                     as: "script", | ||
|  |                     integrity: restProps.integrity | ||
|  |                 } : { | ||
|  |                     as: "script" | ||
|  |                 }); | ||
|  |                 return /*#__PURE__*/ (0, _jsxruntime.jsx)("script", { | ||
|  |                     nonce: nonce, | ||
|  |                     dangerouslySetInnerHTML: { | ||
|  |                         __html: "(self.__next_s=self.__next_s||[]).push(" + JSON.stringify([ | ||
|  |                             src, | ||
|  |                             { | ||
|  |                                 ...restProps, | ||
|  |                                 id | ||
|  |                             } | ||
|  |                         ]) + ")" | ||
|  |                     } | ||
|  |                 }); | ||
|  |             } | ||
|  |         } else if (strategy === "afterInteractive") { | ||
|  |             if (src) { | ||
|  |                 // @ts-ignore
 | ||
|  |                 _reactdom.default.preload(src, restProps.integrity ? { | ||
|  |                     as: "script", | ||
|  |                     integrity: restProps.integrity | ||
|  |                 } : { | ||
|  |                     as: "script" | ||
|  |                 }); | ||
|  |             } | ||
|  |         } | ||
|  |     } | ||
|  |     return null; | ||
|  | } | ||
|  | Object.defineProperty(Script, "__nextScript", { | ||
|  |     value: true | ||
|  | }); | ||
|  | const _default = Script; | ||
|  | 
 | ||
|  | if ((typeof exports.default === 'function' || (typeof exports.default === 'object' && exports.default !== null)) && typeof exports.default.__esModule === 'undefined') { | ||
|  |   Object.defineProperty(exports.default, '__esModule', { value: true }); | ||
|  |   Object.assign(exports.default, exports); | ||
|  |   module.exports = exports.default; | ||
|  | } | ||
|  | 
 | ||
|  | //# sourceMappingURL=script.js.map
 |