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
		
	
| "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
 |