Compare commits

..

9 Commits

Author SHA1 Message Date
d00aa090a6 build: move to esm (wip) 2024-04-16 13:02:45 +08:00
002b2f2701 build: move to esm (wip) 2024-02-28 11:59:34 +08:00
40045135af build: move to esm (wip) 2024-02-27 20:56:03 +08:00
311d588850 chore: update version and readme 2024-02-20 10:58:50 +08:00
2f1910ec87 fix: make inner wrapper fit to the root size (#761) 2024-02-20 10:55:38 +08:00
48a0664c2b chore(deps-dev): bump follow-redirects from 1.15.3 to 1.15.4
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.3 to 1.15.4.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.3...v1.15.4)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-11 17:26:54 +08:00
05ec40a956 chore: improve title 2024-01-02 12:31:56 +08:00
dc9dccbf05 fix: fix postinstall script 2023-12-26 15:21:06 +08:00
476efa4209 fix: add missing type file for 2.7 2023-12-26 15:00:23 +08:00
25 changed files with 692 additions and 609 deletions

View File

@ -1,25 +0,0 @@
module.exports = {
root: true,
env: {
node: true
},
extends: ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/prettier"],
parserOptions: {
ecmaVersion: 2020,
parser: "@typescript-eslint/parser"
},
rules: {
"no-console": process.env.NODE_ENV === "production" ? "warn" : "off",
"no-debugger": process.env.NODE_ENV === "production" ? "warn" : "off",
"vue/multi-word-component-names": "off"
},
overrides: [
{
files: ["*.ts"],
extends: [
"@vue/typescript/recommended",
"@vue/prettier/@typescript-eslint"
]
}
]
};

24
.eslintrc.json Normal file
View File

@ -0,0 +1,24 @@
{
"root": true,
"env": {
"node": true
},
"extends": ["plugin:vue/vue3-essential", "eslint:recommended", "@vue/prettier"],
"parserOptions": {
"ecmaVersion": 2020,
"parser": "@typescript-eslint/parser"
},
"rules": {
"no-console": "off",
"vue/multi-word-component-names": "off"
},
"overrides": [
{
"files": ["*.ts"],
"extends": [
"@vue/typescript/recommended",
"@vue/prettier/@typescript-eslint"
]
}
]
}

View File

@ -1,3 +1,15 @@
## 6.6.9
* Fixed that the chart may not be the same size as the component root element ([#761](https://github.com/ecomfe/vue-echarts/issues/761)).
## 6.6.8
* Fixed the postinstall script to patch the correct `types` entry for Vue 2.7.
## 6.6.7
* Added missing type file for Vue 2.7.
## 6.6.6 ## 6.6.6
* Fixed types for Vue < 2.7. * Fixed types for Vue < 2.7.

View File

@ -236,9 +236,9 @@ Drop `<script>` inside your HTML file and access the component via `window.VueEC
<!-- vue3Scripts:start --> <!-- vue3Scripts:start -->
```html ```html
<script src="https://cdn.jsdelivr.net/npm/vue@3.3.7"></script> <script src="https://cdn.jsdelivr.net/npm/vue@3.4.19"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3"></script> <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.6.5"></script> <script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.6.9"></script>
``` ```
<!-- vue3Scripts:end --> <!-- vue3Scripts:end -->
@ -256,9 +256,9 @@ app.component('v-chart', VueECharts)
<!-- vue2Scripts:start --> <!-- vue2Scripts:start -->
```html ```html
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.15"></script> <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3"></script> <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.6.5"></script> <script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.6.9"></script>
``` ```
<!-- vue2Scripts:end --> <!-- vue2Scripts:end -->

View File

@ -236,9 +236,9 @@ import "echarts";
<!-- vue3Scripts:start --> <!-- vue3Scripts:start -->
```html ```html
<script src="https://cdn.jsdelivr.net/npm/vue@3.3.7"></script> <script src="https://cdn.jsdelivr.net/npm/vue@3.4.19"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3"></script> <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.6.5"></script> <script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.6.9"></script>
``` ```
<!-- vue3Scripts:end --> <!-- vue3Scripts:end -->
@ -256,9 +256,9 @@ app.component('v-chart', VueECharts)
<!-- vue2Scripts:start --> <!-- vue2Scripts:start -->
```html ```html
<script src="https://cdn.jsdelivr.net/npm/vue@2.7.15"></script> <script src="https://cdn.jsdelivr.net/npm/vue@2.7.16"></script>
<script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3"></script> <script src="https://cdn.jsdelivr.net/npm/echarts@5.4.3"></script>
<script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.6.5"></script> <script src="https://cdn.jsdelivr.net/npm/vue-echarts@6.6.9"></script>
``` ```
<!-- vue2Scripts:end --> <!-- vue2Scripts:end -->

View File

@ -1,3 +0,0 @@
module.exports = {
presets: ["@vue/cli-plugin-babel/preset"]
};

3
babel.config.json Normal file
View File

@ -0,0 +1,3 @@
{
"presets": ["@vue/cli-plugin-babel/preset"]
}

View File

@ -1,7 +1,8 @@
{ {
"name": "vue-echarts", "name": "vue-echarts",
"version": "6.6.6", "version": "6.6.9",
"description": "Vue.js component for Apache ECharts.", "type": "module",
"description": "Vue.js component for Apache ECharts™.",
"author": "GU Yiling <justice360@gmail.com>", "author": "GU Yiling <justice360@gmail.com>",
"scripts": { "scripts": {
"serve": "vue-cli-service serve", "serve": "vue-cli-service serve",
@ -28,9 +29,7 @@
"devDependencies": { "devDependencies": {
"@babel/core": "^7.23.2", "@babel/core": "^7.23.2",
"@highlightjs/vue-plugin": "^2.1.0", "@highlightjs/vue-plugin": "^2.1.0",
"@rollup/plugin-node-resolve": "^15.2.3",
"@rollup/plugin-replace": "^5.0.5", "@rollup/plugin-replace": "^5.0.5",
"@rollup/plugin-terser": "^0.4.4",
"@typescript-eslint/eslint-plugin": "^4.33.0", "@typescript-eslint/eslint-plugin": "^4.33.0",
"@typescript-eslint/parser": "^4.33.0", "@typescript-eslint/parser": "^4.33.0",
"@vercel/analytics": "^1.1.1", "@vercel/analytics": "^1.1.1",
@ -45,7 +44,7 @@
"@vueuse/core": "^10.5.0", "@vueuse/core": "^10.5.0",
"comment-mark": "^1.1.1", "comment-mark": "^1.1.1",
"core-js": "^3.33.2", "core-js": "^3.33.2",
"echarts": "^5.4.3", "echarts": "^5.5.0",
"echarts-gl": "^2.0.9", "echarts-gl": "^2.0.9",
"echarts-liquidfill": "^3.1.0", "echarts-liquidfill": "^3.1.0",
"esbuild-wasm": "^0.19.2", "esbuild-wasm": "^0.19.2",
@ -61,10 +60,10 @@
"raw-loader": "^4.0.2", "raw-loader": "^4.0.2",
"resize-detector": "^0.3.0", "resize-detector": "^0.3.0",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"rollup": "^2.79.1", "rollup": "^4.12.0",
"rollup-plugin-dts": "^4.2.3", "rollup-plugin-dts": "^6.1.0",
"rollup-plugin-styles": "^4.0.0", "rollup-plugin-esbuild": "^6.1.1",
"rollup-plugin-ts": "^2.0.7", "rollup-plugin-import-css": "^3.5.0",
"tslib": "^2.6.2", "tslib": "^2.6.2",
"typescript": "4.6.4", "typescript": "4.6.4",
"vue": "^3.3.7", "vue": "^3.3.7",

892
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang=""> <html lang="en-US">
<head> <head>
<meta charset="utf-8"> <meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width,initial-scale=1.0"> <meta name="viewport" content="width=device-width,initial-scale=1.0">
<link rel="icon" href="<%= BASE_URL %>favicon.ico"> <link rel="icon" href="<%= BASE_URL %>favicon.ico">
<link href="https://fonts.googleapis.com/css?family=Inter:300,500;display=swap" rel="stylesheet"> <link href="https://fonts.googleapis.com/css?family=Inter:300,500;display=swap" rel="stylesheet">
<title>Vue-ECharts: Vue.js component for Apache ECharts.</title> <title>Vue-ECharts: Vue.js component for Apache ECharts.</title>
</head> </head>
<body> <body>
<noscript> <noscript>

View File

@ -1,9 +1,8 @@
import typescript from "rollup-plugin-ts"; import esbuild from "rollup-plugin-esbuild";
import terser from "@rollup/plugin-terser"; import { dts } from "rollup-plugin-dts";
import resolve from "@rollup/plugin-node-resolve";
import replace from "@rollup/plugin-replace"; import replace from "@rollup/plugin-replace";
import styles from "rollup-plugin-styles"; import css from "rollup-plugin-import-css";
import { injectVueDemi } from "./scripts/rollup"; import { ignoreCss } from "./scripts/rollup.js";
/** /**
* Modifies the Rollup options for a build to support strict CSP * Modifies the Rollup options for a build to support strict CSP
@ -18,7 +17,7 @@ function configBuild(options, csp) {
result.plugins = [ result.plugins = [
...(csp ? [replace({ __CSP__: `${csp}`, preventAssignment: true })] : []), ...(csp ? [replace({ __CSP__: `${csp}`, preventAssignment: true })] : []),
...plugins, ...plugins,
csp ? styles({ mode: ["extract", "style.css"] }) : styles() csp ? css({ output: "style.css" }) : css({ inject: true })
]; ];
// modify output file names // modify output file names
@ -39,97 +38,37 @@ function configBuild(options, csp) {
const builds = [ const builds = [
{ {
input: "src/index.ts", input: "src/index.ts",
plugins: [ plugins: [esbuild()],
typescript({ external: ["vue-demi", /^echarts/, "resize-detector"],
tsconfig: resolvedConfig => ({ ...resolvedConfig, declaration: true }),
hook: {
outputPath: (path, kind) =>
kind === "declaration" ? "dist/index.d.ts" : path
}
})
],
external: ["vue-demi", "echarts/core", "resize-detector"],
output: {
file: "dist/index.esm.js",
format: "esm",
sourcemap: true
}
},
{
input: "src/index.ts",
plugins: [typescript()],
external: ["vue-demi", "echarts/core", "resize-detector"],
output: [ output: [
{ {
file: "dist/index.esm.min.js", file: "dist/index.esm.js",
format: "esm", format: "esm",
sourcemap: true, sourcemap: true
plugins: [
terser({
format: {
comments: false
}
})
]
}, },
{ {
file: "dist/index.cjs.js", file: "dist/index.cjs.js",
format: "cjs", format: "cjs",
exports: "named", exports: "named",
sourcemap: true sourcemap: true
}
]
},
{
input: "src/index.ts",
plugins: [esbuild({ minify: true })],
external: ["vue-demi", /^echarts/, "resize-detector"],
output: [
{
file: "dist/index.esm.min.js",
format: "esm",
sourcemap: true
}, },
{ {
file: "dist/index.cjs.min.js", file: "dist/index.cjs.min.js",
format: "cjs", format: "cjs",
exports: "named", exports: "named",
sourcemap: true, sourcemap: true
plugins: [
terser({
format: {
comments: false
}
})
]
}
]
},
{
input: "src/global.ts",
plugins: [resolve(), typescript()],
external: ["vue-demi", "echarts", "echarts/core"],
output: [
{
file: "dist/index.umd.js",
format: "umd",
name: "VueECharts",
exports: "default",
sourcemap: true,
globals: {
"vue-demi": "VueDemi",
echarts: "echarts",
"echarts/core": "echarts"
},
plugins: [injectVueDemi]
},
{
file: "dist/index.umd.min.js",
format: "umd",
name: "VueECharts",
exports: "default",
sourcemap: true,
globals: {
"vue-demi": "VueDemi",
echarts: "echarts",
"echarts/core": "echarts"
},
plugins: [
injectVueDemi,
terser({
format: {
comments: false
}
})
]
} }
] ]
} }
@ -137,5 +76,22 @@ const builds = [
export default [ export default [
...builds.map(options => configBuild(options, false)), ...builds.map(options => configBuild(options, false)),
...builds.map(options => configBuild(options, true)) ...builds.map(options => configBuild(options, true)),
{
input: "src/index.ts",
plugins: [
ignoreCss,
dts({
compilerOptions: {
// see https://github.com/unjs/unbuild/pull/57/files
preserveSymlinks: false
}
})
],
external: ["vue-demi", /^echarts/, "resize-detector"],
output: {
file: "dist/index.d.ts",
format: "esm"
}
}
]; ];

View File

@ -9,6 +9,14 @@ const options = [
file: "dist/index.vue2.d.ts", file: "dist/index.vue2.d.ts",
format: "esm" format: "esm"
} }
},
{
input: "src/index.vue2_7.d.ts",
plugins: [dts()],
output: {
file: "dist/index.vue2_7.d.ts",
format: "esm"
}
} }
]; ];

View File

@ -1,17 +1,14 @@
const { readFileSync, writeFileSync } = require("fs"); import { readFileSync, writeFileSync } from "node:fs";
const { resolve } = require("path"); import commentMark from "comment-mark";
const commentMark = require("comment-mark"); import { getPackageMeta, resolvePath } from "./utils";
const { name, version } = require("../package.json");
function resolvePath(...parts) { const { name, version } = getPackageMeta();
return resolve(__dirname, ...parts);
}
const CDN_PREFIX = "https://cdn.jsdelivr.net/npm/"; const CDN_PREFIX = "https://cdn.jsdelivr.net/npm/";
const DEP_VERSIONS = { const DEP_VERSIONS = {
"vue@3": "3.3.7", "vue@3": "3.4.19",
"vue@2": "2.7.15", "vue@2": "2.7.16",
echarts: "5.4.3", echarts: "5.4.3",
[name]: version [name]: version
}; };
@ -41,7 +38,7 @@ const scripts = {
}; };
const README_FILES = ["README.md", "README.zh-Hans.md"].map(name => const README_FILES = ["README.md", "README.zh-Hans.md"].map(name =>
resolvePath("..", name) resolvePath(import.meta.url, "..", name)
); );
README_FILES.forEach(file => { README_FILES.forEach(file => {

View File

@ -1,46 +1,51 @@
/* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-var-requires */
const path = require("path"); import fs from "node:fs";
const fs = require("fs"); import { resolvePath } from "./utils.js";
const packageFile = path.resolve(__dirname, "../package.json"); const packageFile = resolvePath(import.meta.url, "../package.json");
const typesPaths = { const typesPaths = {
3: "dist/index.d.ts", 3: "dist/index.d.ts",
2.7: "dist/index.vue2-7.d.ts", 2.7: "dist/index.vue2_7.d.ts",
2: "dist/index.vue2.d.ts" 2: "dist/index.vue2.d.ts"
}; };
function switchVersion(version) { function switchVersion(version) {
const typesPath = typesPaths[version]; const typesPath = typesPaths[version];
const package = JSON.parse(fs.readFileSync(packageFile, "utf8")); const pkg = JSON.parse(fs.readFileSync(packageFile, "utf8"));
if (typesPath !== package.types) { if (typesPath !== pkg.types) {
package.types = typesPath; pkg.types = typesPath;
fs.writeFileSync(packageFile, JSON.stringify(package, null, " "), "utf8"); fs.writeFileSync(packageFile, JSON.stringify(pkg, null, " "), "utf8");
} }
console.log(`[vue-echarts] Switched to Vue ${version} environment.`); console.log(`[vue-echarts] Switched to Vue ${version} environment.`);
} }
function loadVue() { async function loadVue() {
try { try {
return require("vue"); const Vue = await import("vue");
return Vue;
} catch (e) { } catch (e) {
return null; return null;
} }
} }
const Vue = loadVue(); async function main() {
const Vue = await loadVue();
// Align the process with vue-demi // Align the process with vue-demi
if (!Vue || typeof Vue.version !== "string") { if (!Vue || typeof Vue.version !== "string") {
console.warn( console.warn(
'[vue-echarts] Vue is not found. Please run "npm install vue" to install.' '[vue-echarts] Vue is not found. Please run "npm install vue" to install.'
); );
} else if (Vue.version.startsWith("3.")) { } else if (Vue.version.startsWith("3.")) {
switchVersion(3); switchVersion(3);
} else if (Vue.version.startsWith("2.7.")) { } else if (Vue.version.startsWith("2.7.")) {
switchVersion(2.7); switchVersion(2.7);
} else if (Vue.version.startsWith("2.")) { } else if (Vue.version.startsWith("2.")) {
switchVersion(2); switchVersion(2);
} else { } else {
console.warn(`[vue-echarts] Vue version v${Vue.version} is not supported.`); console.warn(`[vue-echarts] Vue version v${Vue.version} is not supported.`);
}
} }
main();

View File

@ -1,22 +1,7 @@
import { readFileSync } from "fs";
const VUE_DEMI_IIFE = readFileSync(
require.resolve("vue-demi/lib/index.iife.js"),
"utf8"
);
/** @type {import('rollup').Plugin} */
export const injectVueDemi = {
name: "inject-vue-demi",
banner() {
return `${VUE_DEMI_IIFE};\n;`;
}
};
const EMPTY_FILE_ID = "__rollup_empty__"; const EMPTY_FILE_ID = "__rollup_empty__";
/** @type {import('rollup').Plugin} */ /** @type {import('rollup').Plugin} */
export const ingoreCss = { export const ignoreCss = {
name: "ignore-css", name: "ignore-css",
resolveId(source) { resolveId(source) {
if (source.endsWith(".css")) { if (source.endsWith(".css")) {

13
scripts/utils.js Normal file
View File

@ -0,0 +1,13 @@
import { readFileSync } from "node:fs";
import { resolve, dirname } from "node:path";
import { fileURLToPath } from "node:url";
export function resolvePath(url, ...parts) {
return resolve(dirname(fileURLToPath(url)), ...parts);
}
export function getPackageMeta() {
return JSON.parse(
readFileSync(resolvePath(import.meta.url, "/package.json"), "utf8")
);
}

View File

@ -13,11 +13,20 @@ import {
nextTick, nextTick,
watchEffect, watchEffect,
getCurrentInstance, getCurrentInstance,
Vue2, Vue2
type PropType,
type InjectionKey
} from "vue-demi"; } from "vue-demi";
import { init as initChart } from "echarts/core"; import { init as initChart } from "echarts/core";
import {
usePublicAPI,
useAutoresize,
autoresizeProps,
useLoading,
loadingProps
} from "./composables";
import { omitOn, unwrapInjected } from "./utils";
import { register, TAG_NAME } from "./wc";
import type { PropType, InjectionKey } from "vue-demi";
import type { import type {
EChartsType, EChartsType,
EventTarget, EventTarget,
@ -30,15 +39,8 @@ import type {
UpdateOptionsInjection, UpdateOptionsInjection,
Emits Emits
} from "./types"; } from "./types";
import { import type { EChartsElement } from "./wc";
usePublicAPI,
useAutoresize,
autoresizeProps,
useLoading,
loadingProps
} from "./composables";
import { omitOn, unwrapInjected } from "./utils";
import { register, TAG_NAME, type EChartsElement } from "./wc";
import "./style.css"; import "./style.css";
const __CSP__ = false; const __CSP__ = false;
@ -308,7 +310,7 @@ export default defineComponent({
attrs.ref = "root"; attrs.ref = "root";
attrs.class = attrs.class ? ["echarts"].concat(attrs.class) : "echarts"; attrs.class = attrs.class ? ["echarts"].concat(attrs.class) : "echarts";
return h(TAG_NAME, attrs, [ return h(TAG_NAME, attrs, [
h("div", { ref: "inner", class: "echarts-inner" }) h("div", { ref: "inner", class: "vue-echarts-inner" })
]); ]);
} }
}); });

View File

@ -1,6 +1,6 @@
/* eslint-disable @typescript-eslint/no-explicit-any */ /* eslint-disable @typescript-eslint/no-explicit-any */
import { Ref } from "vue-demi"; import type { Ref } from "vue-demi";
import { EChartsType } from "../types"; import type { EChartsType } from "../types";
const METHOD_NAMES = [ const METHOD_NAMES = [
"getWidth", "getWidth",

View File

@ -1,11 +1,10 @@
import { watch, type Ref, type PropType } from "vue-demi"; import { watch } from "vue-demi";
import { throttle } from "echarts/core"; import { throttle } from "echarts/core";
import { import { addListener, removeListener } from "resize-detector";
addListener,
removeListener, import type { Ref, PropType } from "vue-demi";
type ResizeCallback import type { ResizeCallback } from "resize-detector";
} from "resize-detector"; import type { EChartsType } from "../types";
import { type EChartsType } from "../types";
type AutoresizeProp = type AutoresizeProp =
| boolean | boolean

View File

@ -1,12 +1,7 @@
import { inject, computed, watchEffect } from "vue-demi";
import { unwrapInjected } from "../utils"; import { unwrapInjected } from "../utils";
import {
inject, import type { Ref, InjectionKey, PropType } from "vue-demi";
computed,
watchEffect,
type Ref,
type InjectionKey,
type PropType
} from "vue-demi";
import type { EChartsType, LoadingOptions } from "../types"; import type { EChartsType, LoadingOptions } from "../types";
export const LOADING_OPTIONS_KEY = export const LOADING_OPTIONS_KEY =

View File

@ -1,7 +0,0 @@
import "echarts";
import ECharts, * as exported from "./index";
export default {
...ECharts,
...exported
};

View File

@ -1 +1,2 @@
x-vue-echarts,.echarts-inner{display:block;width:100%;height:100%;min-width:0} x-vue-echarts{display:flex;flex-direction:column;width:100%;height:100%;min-width:0}
.vue-echarts-inner{flex-grow:1;min-width:0}

View File

@ -1,6 +1,6 @@
import { init } from "echarts/core"; import { init } from "echarts/core";
import type { Ref } from "vue-demi";
import type { SetOptionOpts, ECElementEvent, ElementEvent } from "echarts"; import type { SetOptionOpts, ECElementEvent, ElementEvent } from "echarts";
import type { Ref } from "vue";
export type Injection<T> = T | null | Ref<T | null> | { value: T | null }; export type Injection<T> = T | null | Ref<T | null> | { value: T | null };

View File

@ -1,4 +1,5 @@
import { unref } from "vue-demi"; import { unref } from "vue-demi";
import type { Injection } from "./types"; import type { Injection } from "./types";
type Attrs = { type Attrs = {

View File

@ -1,7 +1,7 @@
/* eslint-disable @typescript-eslint/no-var-requires */ /* eslint-disable @typescript-eslint/no-var-requires */
const nested = require("postcss-nested"); import nested from "postcss-nested";
module.exports = { export default {
outputDir: "demo", outputDir: "demo",
css: { css: {
loaderOptions: { loaderOptions: {