sveltejs / svelte

web development for the rest of us
https://svelte.dev
MIT License
79.75k stars 4.23k forks source link

svelte next.227 breaks production static build on SvelteKit #13510

Closed ryoppippi closed 1 month ago

ryoppippi commented 1 month ago

Describe the bug

On production build, I got the error like this

Uncaught (in promise) TypeError: s.getAttribute is not a function

works with next.226, still has issue.

The wired thing is that

vite preview --open # works fine
pnpx serve build/ # error

Reproduction

URL: bc5543ca.lp-d1f.pages.dev Repo: https://github.com/vim-jp-radio/

I'll create minimal reproduction later

I can get the file which causes the error: attributes.B_d_bZ2m.js

import {A as w, h as d, R as T, T as l, U as I} from "./runtime.Bein7b5p.js";
import {d as q, e as $, f as B, n as M, g as R} from "./disclose-version.B75eKbpn.js";
function C(s, i) {
    if (i) {
        const o = document.body;
        s.autofocus = !0,
        w( () => {
            document.activeElement === o && s.focus()
        }
        )
    }
}
function D(s, i, o, u) {
    var c = s.__attributes ?? (s.__attributes = {});
    d && (c[i] = s.getAttribute(i),
    i === "src" || i === "srcset" || i === "href" && s.nodeName === "LINK") || c[i] !== (c[i] = o) && (i === "loading" && (s[l] = o),
    o == null ? s.removeAttribute(i) : typeof o != "string" && z(s).includes(i) ? s[i] = o : s.setAttribute(i, o))
}
function P(s, i, o, u, c=!1, g=!1, F=!1) {
    var f = i || {}
      , L = s.tagName === "OPTION";
    for (var p in i)
        p in o || (o[p] = null);
    u !== void 0 && (o.class = o.class ? o.class + " " + u : u);
    var O = z(s)
      , b = s.__attributes ?? (s.__attributes = {})
      , y = [];
    for (const r in o) {
        let a = o[r];
        if (L && r === "value" && a == null) {
            s.value = s.__value = "",
            f[r] = a;
            continue
        }
        var h = f[r];
        if (a !== h) {
            f[r] = a;
            var A = r[0] + r[1];
            if (A !== "$$")
                if (A === "on") {
                    const _ = {}
                      , v = "$$" + r;
                    let t = r.slice(2);
                    var e = R(t);
                    if (q(t) && (t = t.slice(0, -7),
                    _.capture = !0),
                    !e && h) {
                        if (a != null)
                            continue;
                        s.removeEventListener(t, f[v], _),
                        f[v] = null
                    }
                    if (a != null)
                        if (e)
                            s[`__${t}`] = a,
                            B([t]);
                        else {
                            let N = function(E) {
                                f[r].call(this, E)
                            };
                            i ? f[v] = $(t, s, N, _) : y.push([r, a, () => f[v] = $(t, s, N, _)])
                        }
                } else if (r === "style" && a != null)
                    s.style.cssText = a + "";
                else if (r === "autofocus")
                    C(s, !!a);
                else if (r === "__value" || r === "value" && a != null)
                    s.value = s[r] = s.__value = a;
                else {
                    var n = r;
                    c || (n = M(n)),
                    a == null && !g ? (b[r] = null,
                    s.removeAttribute(r)) : O.includes(n) && (g || typeof a != "string") ? s[n] = a : typeof a != "function" && (d && (n === "src" || n === "href" || n === "srcset") || D(s, n, a))
                }
        }
    }
    return i || w( () => {
        if (s.isConnected)
            for (const [r,a,_] of y)
                f[r] === a && _()
    }
    ),
    f
}
var k = new Map;
function z(s) {
    var i = k.get(s.nodeName);
    if (i)
        return i;
    k.set(s.nodeName, i = []);
    for (var o, u = T(s); u.constructor.name !== "Element"; ) {
        o = I(u);
        for (var c in o)
            o[c].set && i.push(c);
        u = T(u)
    }
    return i
}
function S(s) {
    if (!d && s.loading === "lazy") {
        var i = s.src;
        s[l] = null,
        s.loading = "eager",
        s.removeAttribute("src"),
        requestAnimationFrame( () => {
            s[l] !== "eager" && (s.loading = "lazy"),
            s.src = i
        }
        )
    }
}
export {P as a, S as h, D as s};

Logs

No response

System Info

System:
    OS: macOS 15.0.1
    CPU: (11) arm64 Apple M3 Pro
    Memory: 1.67 GB / 36.00 GB
    Shell: 3.7.1 - /opt/homebrew/bin/fish
  Binaries:
    Node: 22.8.0 - ~/.local/share/devbox/global/default/.devbox/nix/profile/default/bin/node
    npm: 10.8.2 - ~/.local/share/devbox/global/default/.devbox/nix/profile/default/bin/npm
    pnpm: 9.11.0 - ~/.local/share/devbox/global/default/.devbox/nix/profile/default/bin/pnpm
    bun: 1.1.29 - ~/.local/share/aquaproj-aqua/bin/bun
  Browsers:
    Chrome: 129.0.6668.90
    Safari: 18.0.1


### Severity

annoyance
ryoppippi commented 1 month ago

I build with minify=false option Maybe: https://github.com/sveltejs/svelte/blob/14ecedf33b04d74396372e93ffb0458b36b57761/packages/svelte/src/internal/client/dom/elements/attributes.js#L88

import { q as queue_micro_task, h as hydrating, B as get_prototype_of, L as LOADING_ATTR_SYMBOL, C as get_descriptors } from "./runtime.B7Evkmdu.js";
import { d as is_capture_event, e as create_event, f as delegate, n as normalize_attribute, g as is_delegated } from "./disclose-version.hcw21kbQ.js";
function autofocus(dom, value) {
  if (value) {
    const body = document.body;
    dom.autofocus = true;
    queue_micro_task(() => {
      if (document.activeElement === body) {
        dom.focus();
      }
    });
  }
}
function set_attribute(element, attribute, value, skip_warning) {
  var attributes = element.__attributes ?? (element.__attributes = {});
  if (hydrating) {
    attributes[attribute] = element.getAttribute(attribute);  //causes an error!!!!
    if (attribute === "src" || attribute === "srcset" || attribute === "href" && element.nodeName === "LINK") {
      return;
    }
  }
  if (attributes[attribute] === (attributes[attribute] = value)) return;
  if (attribute === "loading") {
    element[LOADING_ATTR_SYMBOL] = value;
  }
  if (value == null) {
    element.removeAttribute(attribute);
  } else if (typeof value !== "string" && get_setters(element).includes(attribute)) {
    element[attribute] = value;
  } else {
    element.setAttribute(attribute, value);
  }
}
function set_attributes(element, prev, next, css_hash, preserve_attribute_case = false, skip_warning) {
  var current = prev || {};
  var is_option_element = element.tagName === "OPTION";
  for (var key in prev) {
    if (!(key in next)) {
      next[key] = null;
    }
  }
  if (css_hash !== void 0) {
    next.class = next.class ? next.class + " " + css_hash : css_hash;
  }
  var setters = setters_cache.get(element.nodeName);
  if (!setters) setters_cache.set(element.nodeName, setters = get_setters(element));
  var attributes = (
    /** @type {Record<string, unknown>} **/
    element.__attributes ?? (element.__attributes = {})
  );
  var events = [];
  for (const key2 in next) {
    let value = next[key2];
    if (is_option_element && key2 === "value" && value == null) {
      element.value = element.__value = "";
      current[key2] = value;
      continue;
    }
    var prev_value = current[key2];
    if (value === prev_value) continue;
    current[key2] = value;
    var prefix = key2[0] + key2[1];
    if (prefix === "$$") continue;
    if (prefix === "on") {
      const opts = {};
      const event_handle_key = "$$" + key2;
      let event_name = key2.slice(2);
      var delegated = is_delegated(event_name);
      if (is_capture_event(event_name)) {
        event_name = event_name.slice(0, -7);
        opts.capture = true;
      }
      if (!delegated && prev_value) {
        if (value != null) continue;
        element.removeEventListener(event_name, current[event_handle_key], opts);
        current[event_handle_key] = null;
      }
      if (value != null) {
        if (!delegated) {
          let handle = function(evt) {
            current[key2].call(this, evt);
          };
          if (!prev) {
            events.push([
              key2,
              value,
              () => current[event_handle_key] = create_event(event_name, element, handle, opts)
            ]);
          } else {
            current[event_handle_key] = create_event(event_name, element, handle, opts);
          }
        } else {
          element[`__${event_name}`] = value;
          delegate([event_name]);
        }
      }
    } else if (value == null) {
      attributes[key2] = null;
      element.removeAttribute(key2);
    } else if (key2 === "style") {
      element.style.cssText = value + "";
    } else if (key2 === "autofocus") {
      autofocus(
        /** @type {HTMLElement} */
        element,
        Boolean(value)
      );
    } else if (key2 === "__value" || key2 === "value") {
      element.value = element[key2] = element.__value = value;
    } else {
      var name = key2;
      if (!preserve_attribute_case) {
        name = normalize_attribute(name);
      }
      if (setters.includes(name) && typeof value !== "string") {
        element[name] = value;
      } else if (typeof value !== "function") {
        if (hydrating && (name === "src" || name === "href" || name === "srcset")) ;
        else {
          set_attribute(element, name, value);
        }
      }
    }
  }
  if (!prev) {
    queue_micro_task(() => {
      if (!element.isConnected) return;
      for (const [key2, value, evt] of events) {
        if (current[key2] === value) {
          evt();
        }
      }
    });
  }
  return current;
}
var setters_cache = /* @__PURE__ */ new Map();
function get_setters(element) {
  var setters = [];
  var descriptors;
  var proto = get_prototype_of(element);
  while (proto.constructor.name !== "Element") {
    descriptors = get_descriptors(proto);
    for (var key in descriptors) {
      if (descriptors[key].set) {
        setters.push(key);
      }
    }
    proto = get_prototype_of(proto);
  }
  return setters;
}
function handle_lazy_img(element) {
  if (!hydrating && element.loading === "lazy") {
    var src = element.src;
    element[LOADING_ATTR_SYMBOL] = null;
    element.loading = "eager";
    element.removeAttribute("src");
    requestAnimationFrame(() => {
      if (element[LOADING_ATTR_SYMBOL] !== "eager") {
        element.loading = "lazy";
      }
      element.src = src;
    });
  }
}
export {
  set_attributes as a,
  handle_lazy_img as h,
  set_attribute as s
};
ryoppippi commented 1 month ago

Got this issue with https://github.com/ntsd/sveltekit-html-minifier So, I'll create an issue for that

dummdidumm commented 1 month ago

That sounds like you're removing whitespace and/or comments via the minifier, which Svelte is sensitive to. Try turning those parts off.

ryoppippi commented 1 month ago

@dummdidumm Thanks for the info. I'll try the options later. For now, I'll turn off the minifier