そろそろ使えそうな import attributes は現状 caniuse で次の様な状態となります。 主要だと firefox だけダメみたいですね。(safari も css は対応していない模様?)
で、 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 を渡せることを確認すると動作するかがわかります。
サンプル
※ png / gif は存在しない type として使っているだけです。( safari だと css import が対応していないからそこらへんはままわかるか……?
ソース
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.