0
0

そろそろ大分ブラウザで使える様になった import attributes の話 (もしくは import ... with {type:json / css} の話)

Posted at

そろそろ使えそうな import attributes は現状 caniuse で次の様な状態となります。 主要だと firefox だけダメみたいですね。
image.png

で、 import attribute って何なの?

プロポーザル

MDN

具体例

具体的に言うと次の様な構文です。 type は css と json が定義されています。

// css の読み込み
import styles from 'https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css' with { type: 'css' };
// json の読み込み
import products from 'https://endoflife.date/api/windows.json' with {type:'json'};
// この取得した css は 次の様に適用することができる
document.adoptedStyleSheets = [styles];
// json を画面に表示している
document.getElementById('json').innerText = JSON.stringify(products);

動作サンプル

ソース
import styles from 'https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css' with { type: 'css' };
import products from 'https://endoflife.date/api/windows.json' with {type:'json'};
console.log(styles);
console.log(products);
document.adoptedStyleSheets = [styles];
json.innerText = JSON.stringify(products);

See the Pen import attribute test by juner clarinet (@juner) on CodePen.

どこまで動作するかを調査するなら

dynamic import における import() メソッドに 第二引数が渡せること、それと type を渡せることを確認すると動作するかがわかります。

サンプル

ソース
import noop from "https://esm.sh/noop@1.0.1";
// #region type data
/** use types key:[type, dataUrl, isValid] */
const types = {
  json: [
    "json",
    "data:application/json;base64,e30=",
    (v) => v && JSON.stringify(v) === "{}"
  ],
  css: [
    "css",
    "data:text/css;base64,e30=",
    (v) =>
      typeof globalThis.CSSStyleSheet === "function" &&
      v instanceof CSSStyleSheet
  ],
  png: [
    "png",
    "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQYV2NgYGD4DwABBAEAcCBlCwAAAABJRU5ErkJggg==",
    true
  ],
  gif: [
    "gif",
    "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAQAAAC1HAwCAAAAC0lEQVQI12NgYAAAAAMAASDVlMcAAAAASUVORK5CYII=",
    true
  ]
};
// #endregion
/**
 * import attribute support check function
 * @param {[type: string, dataUrl: string, ok:boolean]}
 * @return {[supported: true, 'ok']|[supported: false, error:Error]}
 */
export async function enableWithTypeSyntax([type, dataUrl, ok]) {
  let enableWithTypeSyntax = false;
  const option = (() => {
    const option = {};
    const w = {
      type
    };
    Reflect.defineProperty(option, "with", {
      get: () => ((enableWithTypeSyntax = true), w)
    });
    return option;
  })();
  let result;
  try {
    const importMethod = new Function(
      "dataUrl",
      "option",
      "return import(dataUrl, option);"
    );
    result = await importMethod(dataUrl, option);
    if (!enableWithTypeSyntax) return [false, new Error("not with read.")];
    const isValid =
      typeof ok === "function" ? ok(result?.["default"], result) : !!ok;
    if (!isValid)
      return [
        false,
        new Error("type is invalid", {
          cause: {
            default: result?.default,
            module: result
          }
        })
      ];
    return [true, "ok"];
  } catch (e) {
    if (e instanceof SyntaxError)
      return [
        false,
        new Error("not supported. import attribute syntax", {
          cause: e
        })
      ];
    return [false, e];
  }
}
if (
  globalThis.template instanceof HTMLTemplateElement &&
  globalThis.target instanceof HTMLElement
) {
  for (const [typeName, settings] of Object.entries(types)) {
    const [supported, message] = await enableWithTypeSyntax(settings);
    outputSupportStatus(typeName, supported, message);
    if (message instanceof Error)
      console.error({typeName, supported, message});
    else
      console.log({typeName, supported, message});
  }

  function outputSupportStatus(typeName, supported, message) {
    const node = template.content.cloneNode(true);
    node.querySelector("tr").classList.add(supported ? "ok" : "ng");
    node.querySelector(".type").innerText = typeName;
    node.querySelector(".supported").innerText = supported
      ? "enable"
      : "disable";
    node.querySelector(".message").innerText = message?.message
      ? message?.message
      : message;
    target.appendChild(node);
  }
}

See the Pen import with testing by juner clarinet (@juner) on CodePen.

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0