PageSourceSearch

https://www.gschargev.co.kr/flutter.js

js gschargev.co.kr collected 2026-09-24 12:22:59 UTC 14,240 bytes, 383 lines download raw bytes

1// Copyright 2014 The Flutter Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5if (!_flutter) {
6  var _flutter = {};
7}
8_flutter.loader = null;
9
10(function () {
11  "use strict";
12
13  const baseUri = ensureTrailingSlash(getBaseURI());
14
15  function getBaseURI() {
16    const base = document.querySelector("base");
17    return (base && base.getAttribute("href")) || "";
18  }
19
20  function ensureTrailingSlash(uri) {
21    if (uri == "") {
22      return uri;
23    }
24    return uri.endsWith("/") ? uri : `${uri}/`;
25  }
26
27  /**
28   * Wraps `promise` in a timeout of the given `duration` in ms.
29   *
30   * Resolves/rejects with whatever the original `promises` does, or rejects
31   * if `promise` takes longer to complete than `duration`. In that case,
32   * `debugName` is used to compose a legible error message.
33   *
34   * If `duration` is < 0, the original `promise` is returned unchanged.
35   * @param {Promise} promise
36   * @param {number} duration
37   * @param {string} debugName
38   * @returns {Promise} a wrapped promise.
39   */
40  async function timeout(promise, duration, debugName) {
41    if (duration < 0) {
42      return promise;
43    }
44    let timeoutId;
45    const _clock = new Promise((_, reject) => {
46      timeoutId = setTimeout(() => {
47        reject(
48          new Error(
49            `${debugName} took more than ${duration}ms to resolve. Moving on.`,
50            {
51              cause: timeout,
52            }
53          )
54        );
55      }, duration);
56    });
57
58    return Promise.race([promise, _clock]).finally(() => {
59      clearTimeout(timeoutId);
60    });
61  }
62
63  /**
64   * Handles the creation of a TrustedTypes `policy` that validates URLs based
65   * on an (optional) incoming array of RegExes.
66   */
67  class FlutterTrustedTypesPolicy {
68    /**
69     * Constructs the policy.
70     * @param {[RegExp]} validPatterns the patterns to test URLs
71     * @param {String} policyName the policy name (optional)
72     */
73    constructor(validPatterns, policyName = "flutter-js") {
74      const patterns = validPatterns || [
75        /\.js$/,
76      ];
77      if (window.trustedTypes) {
78        this.policy = trustedTypes.createPolicy(policyName, {
79          createScriptURL: function(url) {
80            const parsed = new URL(url, window.location);
81            const file = parsed.pathname.split("/").pop();
82            const matches = patterns.some((pattern) => pattern.test(file));
83            if (matches) {
84              return parsed.toString();
85            }
86            console.error(
87              "URL rejected by TrustedTypes policy",
88              policyName, ":", url, "(download prevented)");
89          }
90        });
91      }
92    }
93  }
94
95  /**
96   * Handles loading/reloading Flutter's service worker, if configured.
97   *
98   * @see: https://developers.google.com/web/fundamentals/primers/service-workers
99   */
100  class FlutterServiceWorkerLoader {
101    /**
102     * Injects a TrustedTypesPolicy (or undefined if the feature is not supported).
103     * @param {TrustedTypesPolicy | undefined} policy
104     */
105    setTrustedTypesPolicy(policy) {
106      this._ttPolicy = policy;
107    }
108
109    /**
110     * Returns a Promise that resolves when the latest Flutter service worker,
111     * configured by `settings` has been loaded and activated.
112     *
113     * Otherwise, the promise is rejected with an error message.
114     * @param {*} settings Service worker settings
115     * @returns {Promise} that resolves when the latest serviceWorker is ready.
116     */
117    loadServiceWorker(settings) {
118      if (settings == null) {
119        // In the future, settings = null -> uninstall service worker?
120        console.debug("Null serviceWorker configuration. Skipping.");
121        return Promise.resolve();
122      }
123      if (!("serviceWorker" in navigator)) {
124        let errorMessage = "Service Worker API unavailable.";
125        if (!window.isSecureContext) {
126          errorMessage += "\nThe current context is NOT secure."
127          errorMessage += "\nRead more: https://developer.mozilla.org/en-US/docs/Web/Security/Secure_Contexts";
128        }
129        return Promise.reject(
130          new Error(errorMessage)
131        );
132      }
133      const {
134        serviceWorkerVersion,
135        serviceWorkerUrl = `${baseUri}flutter_service_worker.js?v=${serviceWorkerVersion}`,
136        timeoutMillis = 4000,
137      } = settings;
138
139      // Apply the TrustedTypes policy, if present.
140      let url = serviceWorkerUrl;
141      if (this._ttPolicy != null) {
142        url = this._ttPolicy.createScriptURL(url);
143      }
144
145      const serviceWorkerActivation = navigator.serviceWorker
146        .register(url)
147        .then(this._getNewServiceWorker)
148        .then(this._waitForServiceWorkerActivation);
149
150      // Timeout race promise
151      return timeout(
152        serviceWorkerActivation,
153        timeoutMillis,
154        "prepareServiceWorker"
155      );
156    }
157
158    /**
159     * Returns the latest service worker for the given `serviceWorkerRegistrationPromise`.
160     *
161     * This might return the current service worker, if there's no new service worker
162     * awaiting to be installed/updated.
163     *
164     * @param {Promise<ServiceWorkerRegistration>} serviceWorkerRegistrationPromise
165     * @returns {Promise<ServiceWorker>}
166     */
167    async _getNewServiceWorker(serviceWorkerRegistrationPromise) {
168      const reg = await serviceWorkerRegistrationPromise;
169
170      if (!reg.active && (reg.installing || reg.waiting)) {
171        // No active web worker and we have installed or are installing
172        // one for the first time. Simply wait for it to activate.
173        console.debug("Installing/Activating first service worker.");
174        return reg.installing || reg.waiting;
175      } else if (!reg.active.scriptURL.endsWith(serviceWorkerVersion)) {
176        // When the app updates the serviceWorkerVersion changes, so we
177        // need to ask the service worker to update.
178        return reg.update().then((newReg) => {
179          console.debug("Updating service worker.");
180          return newReg.installing || newReg.waiting || newReg.active;
181        });
182      } else {
183        console.debug("Loading from existing service worker.");
184        return reg.active;
185      }
186    }
187
188    /**
189     * Returns a Promise that resolves when the `latestServiceWorker` changes its
190     * state to "activated".
191     *
192     * @param {Promise<ServiceWorker>} latestServiceWorkerPromise
193     * @returns {Promise<void>}
194     */
195    async _waitForServiceWorkerActivation(latestServiceWorkerPromise) {
196      const serviceWorker = await latestServiceWorkerPromise;
197
198      if (!serviceWorker || serviceWorker.state == "activated") {
199        if (!serviceWorker) {
200          return Promise.reject(
201            new Error("Cannot activate a null service worker!")
202          );
203        } else {
204          console.debug("Service worker already active.");
205          return Promise.resolve();
206        }
207      }
208      return new Promise((resolve, _) => {
209        serviceWorker.addEventListener("statechange", () => {
210          if (serviceWorker.state == "activated") {
211            console.debug("Activated new service worker.");
212            resolve();
213          }
214        });
215      });
216    }
217  }
218
219  /**
220   * Handles injecting the main Flutter web entrypoint (main.dart.js), and notifying
221   * the user when Flutter is ready, through `didCreateEngineInitializer`.
222   *
223   * @see https://docs.flutter.dev/development/platform-integration/web/initialization
224   */
225  class FlutterEntrypointLoader {
226    /**
227     * Creates a FlutterEntrypointLoader.
228     */
229    constructor() {
230      // Watchdog to prevent injecting the main entrypoint multiple times.
231      this._scriptLoaded = false;
232    }
233
234    /**
235     * Injects a TrustedTypesPolicy (or undefined if the feature is not supported).
236     * @param {TrustedTypesPolicy | undefined} policy
237     */
238    setTrustedTypesPolicy(policy) {
239      this._ttPolicy = policy;
240    }
241
242    /**
243     * Loads flutter main entrypoint, specified by `entrypointUrl`, and calls a
244     * user-specified `onEntrypointLoaded` callback with an EngineInitializer
245     * object when it's done.
246     *
247     * @param {*} options
248     * @returns {Promise | undefined} that will eventually resolve with an
249     * EngineInitializer, or will be rejected with the error caused by the loader.
250     * Returns undefined when an `onEntrypointLoaded` callback is supplied in `options`.
251     */
252    async loadEntrypoint(options) {
253      const { entrypointUrl = `${baseUri}main.dart.js`, onEntrypointLoaded } =
254        options || {};
255
256      return this._loadEntrypoint(entrypointUrl, onEntrypointLoaded);
257    }
258
259    /**
260     * Resolves the promise created by loadEntrypoint, and calls the `onEntrypointLoaded`
261     * function supplied by the user (if needed).
262     *
263     * Called by Flutter through `_flutter.loader.didCreateEngineInitializer` method,
264     * which is bound to the correct instance of the FlutterEntrypointLoader by
265     * the FlutterLoader object.
266     *
267     * @param {Function} engineInitializer @see https://github.com/flutter/engine/blob/main/lib/web_ui/lib/src/engine/js_interop/js_loader.dart#L42
268     */
269    didCreateEngineInitializer(engineInitializer) {
270      if (typeof this._didCreateEngineInitializerResolve === "function") {
271        this._didCreateEngineInitializerResolve(engineInitializer);
272        // Remove the resolver after the first time, so Flutter Web can hot restart.
273        this._didCreateEngineInitializerResolve = null;
274        // Make the engine revert to "auto" initialization on hot restart.
275        delete _flutter.loader.didCreateEngineInitializer;
276      }
277      if (typeof this._onEntrypointLoaded === "function") {
278        this._onEntrypointLoaded(engineInitializer);
279      }
280    }
281
282    /**
283     * Injects a script tag into the DOM, and configures this loader to be able to
284     * handle the "entrypoint loaded" notifications received from Flutter web.
285     *
286     * @param {string} entrypointUrl the URL of the script that will initialize
287     *                 Flutter.
288     * @param {Function} onEntrypointLoaded a callback that will be called when
289     *                   Flutter web notifies this object that the entrypoint is
290     *                   loaded.
291     * @returns {Promise | undefined} a Promise that resolves when the entrypoint
292     *                                is loaded, or undefined if `onEntrypointLoaded`
293     *                                is a function.
294     */
295    _loadEntrypoint(entrypointUrl, onEntrypointLoaded) {
296      const useCallback = typeof onEntrypointLoaded === "function";
297
298      if (!this._scriptLoaded) {
299        this._scriptLoaded = true;
300        const scriptTag = this._createScriptTag(entrypointUrl);
301        if (useCallback) {
302          // Just inject the script tag, and return nothing; Flutter will call
303          // `didCreateEngineInitializer` when it's done.
304          console.debug("Injecting <script> tag. Using callback.");
305          this._onEntrypointLoaded = onEntrypointLoaded;
306          document.body.append(scriptTag);
307        } else {
308          // Inject the script tag and return a promise that will get resolved
309          // with the EngineInitializer object from Flutter when it calls
310          // `didCreateEngineInitializer` later.
311          return new Promise((resolve, reject) => {
312            console.debug(
313              "Injecting <script> tag. Using Promises. Use the callback approach instead!"
314            );
315            this._didCreateEngineInitializerResolve = resolve;
316            scriptTag.addEventListener("error", reject);
317            document.body.append(scriptTag);
318          });
319        }
320      }
321    }
322
323    /**
324     * Creates a script tag for the given URL.
325     * @param {string} url
326     * @returns {HTMLScriptElement}
327     */
328    _createScriptTag(url) {
329      const scriptTag = document.createElement("script");
330      scriptTag.type = "application/javascript";
331      // Apply TrustedTypes validation, if available.
332      let trustedUrl = url;
333      if (this._ttPolicy != null) {
334        trustedUrl = this._ttPolicy.createScriptURL(url);
335      }
336      scriptTag.src = trustedUrl;
337      return scriptTag;
338    }
339  }
340
341  /**
342   * The public interface of _flutter.loader. Exposes two methods:
343   * * loadEntrypoint (which coordinates the default Flutter web loading procedure)
344   * * didCreateEngineInitializer (which is called by Flutter to notify that its
345   *                              Engine is ready to be initialized)
346   */
347  class FlutterLoader {
348    /**
349     * Initializes the Flutter web app.
350     * @param {*} options
351     * @returns {Promise?} a (Deprecated) Promise that will eventually resolve
352     *                     with an EngineInitializer, or will be rejected with
353     *                     any error caused by the loader. Or Null, if the user
354     *                     supplies an `onEntrypointLoaded` Function as an option.
355     */
356    async loadEntrypoint(options) {
357      const { serviceWorker, ...entrypoint } = options || {};
358
359      // A Trusted Types policy that is going to be used by the loader.
360      const flutterTT = new FlutterTrustedTypesPolicy();
361
362      // The FlutterServiceWorkerLoader instance could be injected as a dependency
363      // (and dynamically imported from a module if not present).
364      const serviceWorkerLoader = new FlutterServiceWorkerLoader();
365      serviceWorkerLoader.setTrustedTypesPolicy(flutterTT.policy);
366      await serviceWorkerLoader.loadServiceWorker(serviceWorker).catch(e => {
367        // Regardless of what happens with the injection of the SW, the show must go on
368        console.warn("Exception while loading service worker:", e);
369      });
370
371      // The FlutterEntrypointLoader instance could be injected as a dependency
372      // (and dynamically imported from a module if not present).
373      const entrypointLoader = new FlutterEntrypointLoader();
374      entrypointLoader.setTrustedTypesPolicy(flutterTT.policy);
375      // Install the `didCreateEngineInitializer` listener where Flutter web expects it to be.
376      this.didCreateEngineInitializer =
377        entrypointLoader.didCreateEngineInitializer.bind(entrypointLoader);
378      return entrypointLoader.loadEntrypoint(entrypoint);
379    }
380  }
381
382  _flutter.loader = new FlutterLoader();
383})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.