From cebb30b2a766bcaca6a7fe62514b2c9019d463f9 Mon Sep 17 00:00:00 2001 From: Owen Buckley Date: Fri, 13 Feb 2026 19:33:03 -0500 Subject: [PATCH 1/7] docs: add vitest logo to home page --- src/assets/vitest.svg | 5 +++++ src/components/build-with-friends/build-with-friends.js | 4 ++++ 2 files changed, 9 insertions(+) create mode 100644 src/assets/vitest.svg diff --git a/src/assets/vitest.svg b/src/assets/vitest.svg new file mode 100644 index 00000000..d230a3b6 --- /dev/null +++ b/src/assets/vitest.svg @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/src/components/build-with-friends/build-with-friends.js b/src/components/build-with-friends/build-with-friends.js index c03a37cf..783344d1 100644 --- a/src/components/build-with-friends/build-with-friends.js +++ b/src/components/build-with-friends/build-with-friends.js @@ -5,6 +5,7 @@ import openPropsIcon from "../../assets/open-props.svg?type=raw"; import storybookIcon from "../../assets/storybook.svg?type=raw"; import tailwindIcon from "../../assets/tailwind-logo.svg?type=raw"; import typescriptIcon from "../../assets/typescript.svg?type=raw"; +import vitestIcon from "../../assets/vitest.svg?type=raw"; import wccIcon from "../../assets/wcc.svg?type=raw"; import wtrIcon from "../../assets/modern-web.svg?type=raw"; @@ -43,6 +44,9 @@ export default class BuildWithFriends extends HTMLElement { ${openPropsIcon} Open Props + + ${vitestIcon} + `; From b915d4b9db250dff3360095a671e42c9c33cf627 Mon Sep 17 00:00:00 2001 From: Owen Buckley Date: Fri, 13 Feb 2026 20:29:15 -0500 Subject: [PATCH 2/7] docs: finish up vitest guide --- src/pages/guides/ecosystem/vitest.md | 434 +++++++++++++++++++++++++++ 1 file changed, 434 insertions(+) create mode 100644 src/pages/guides/ecosystem/vitest.md diff --git a/src/pages/guides/ecosystem/vitest.md b/src/pages/guides/ecosystem/vitest.md new file mode 100644 index 00000000..a173b262 --- /dev/null +++ b/src/pages/guides/ecosystem/vitest.md @@ -0,0 +1,434 @@ +--- +layout: guides +order: 6 +tocHeading: 2 +--- + +# Vitest + +[**Vitest**](https://vitest.dev/) is a test runner based on [**Vite**](https://vite.dev/). This guide will give a high level overview of setting up Vitest to test your Web Components and how to integrate any Greenwood plugins you are using as Vite plugins. + +> You can see an example [here](https://github.com/ProjectEvergreen/wcc) in the docs/ folder. + +## Setup + +> At time of writing, this guide was based on Vitest v4.x and Vite v7.x. + +Install Vite and Vitest: + + + + + + ```shell + npm i -D vite vitest + ``` + + ```shell + yarn add vite vitest --save-dev + ``` + + ```shell + pnpm add -D vite vitest + ``` + + + + + +Next, let's create a _vitest.config.js_ file and configure the location of our test cases: + + + + + + ```js + import { defineConfig } from 'vitest/config'; + + export default defineConfig({ + test: { + include: ['./src/**/*.test.ts'] + }, + }); + ``` + + + + + +Lastly, let's create some NPM scripts to run our tests. By default, vitest will run in watch mode which is great for TDD (Test Driven Development). + +Below is an example of how to setup NPM scripts for development: + + + + + + ```json + { + "test:docs": "vitest run --coverage", + "test:docs:tdd": "vitest" + } + ``` + + + + + +## Browser Testing + +The best way to test Web Components is in a browser. For this guide, we will use [**Playwright**](https://playwright.dev/) as a headless browser to run our tests in. + + + + + + ```shell + npm i -D playwright @vitest/browser-playwright + ``` + + ```shell + yarn add playwright @vitest/browser-playwright --save-dev + ``` + + ```shell + pnpm add -D playwright @vitest/browser-playwright + ``` + + + + + +Then install Playwright + + + + + + ```shell + $ npx playwright install + ``` + + + + + +Then in our _vitest.config.js_ file, let's add configuration for Playwright: + + + + + + ```js + import { defineConfig } from 'vitest/config'; + import { playwright } from '@vitest/browser-playwright'; + + export default defineConfig({ + test: { + include: ['./src/**/*.test.ts'], + browser: { + provider: playwright(), + enabled: true, + headless: true, + instances: [{ browser: 'chromium' }], + screenshotFailures: false, + }, + }, + }); + ``` + + + + + +> Note: For CI environments like GitHub Actions, you'll want to add a step for install Playwright include deps +> +> ```shell +> npx playwright install --with-deps +> ``` + +## Usage + +You should now be good to start writing your first test! ⚡ + + + + + + ```js + export default class Footer extends HTMLElement { + connectedCallback() { + this.innerHTML = ` +
+

Greenwood

+ +
+ `; + } + } + + customElements.define("app-footer", Footer); + ``` + +
+ + + + + + + + ```js + import { describe, it, expect, beforeEach, afterEach } from 'vitest'; + import './footer.tsx'; + + describe('Components/Footer', () => { + let footer; + + describe('Default Behavior', () => { + beforeEach(() => { + footer = document.createElement('app-footer'); + + document.body.appendChild(footer); + }); + + it('should not be undefined', () => { + expect(footer).not.equal(undefined); + expect(footer.querySelectorAll('footer').length).equal(1); + }); + + it('should have a link for to the home page', () => { + const heading = footer.querySelectorAll('h4'); + + expect(heading.length).equal(1); + expect(heading[0].textContent).equal('Greenwood'); + }); + + it('should have the Greenwood logo image', () => { + const logo = footer.querySelectorAll('img'); + + expect(logo.length).equal(1); + expect(logo[0].getAttribute('src')).equal('/assets/greenwood-logo.webp'); + }); + }); + + afterEach(() => { + footer.remove(); + footer = undefined; + }); + }); + ``` + + + + + +## Import Attributes + +As [Vite does not support Import Attributes](https://github.com/vitejs/vite/issues/14674), we will need to update our _vitest.config.js_ file and write a [custom plugin](https://vitejs.dev/guide/api-plugin) to work around this. + +In this example we are handling for CSS Module scripts: + + + + + + ```js + import { defineConfig } from 'vitest/config'; + import fs from "node:fs/promises"; + import path from "node:path"; + // 1) import the greenwood plugin and lifecycle helpers + import { greenwoodPluginStandardCss } from "@greenwood/cli/src/plugins/resource/plugin-standard-css.js"; + import { readAndMergeConfig } from "@greenwood/cli/src/lifecycles/config.js"; + import { initContext } from "@greenwood/cli/src/lifecycles/context.js"; + + // 2) initialize Greenwood lifecycles + const config = await readAndMergeConfig(); + const context = await initContext({ config }); + const compilation = { context, config }; + + // 3) initialize the plugin + const standardCssResource = greenwoodPluginStandardCss.provider(compilation); + + // 4) customize Vite + function transformConstructableStylesheetsPlugin() { + return { + name: "transform-constructable-stylesheets", + enforce: "pre", + resolveId: (id, importer) => { + if ( + // you'll need to configure this `importer` line to the location of your own components + importer?.indexOf("/src/components/") >= 0 && + id.endsWith(".css") && + !id.endsWith(".module.css") + ) { + // append .type to the end of Constructable Stylesheet file paths so that they are not automatically precessed by Vite's default pipeline + return path.join(path.dirname(importer), `${id}.type`); + } + }, + load: async (id) => { + if (id.endsWith(".css.type")) { + const filename = id.slice(0, -5); + const contents = await fs.readFile(filename, "utf-8"); + const url = new URL(`file://${id.replace(".type", "")}`); + // "coerce" native constructable stylesheets into inline JS so Vite / Rollup do not complain + const request = new Request(url, { + headers: { + Accept: "text/javascript", + }, + }); + const response = await standardCssResource.intercept(url, request, new Response(contents)); + const body = await response.text(); + + return body; + } + }, + }; + } + + export default defineConfig({ + test: { /* ... */ }, + + // 5) add it the plugins option + plugins: [transformConstructableStylesheetsPlugin()], + }); + ``` + + + + + +Phew, should be all set now. + +## Resource Plugins + +If you're using one of Greenwood's [resource plugins](/docs/plugins/), you'll want to update the _vitest.config.js_ file so we can create a custom transformation plugin that can leverage Greenwood's plugins to automatically handle custom transformations. + +For example, if you're using Greenwood's [Raw Plugin](https://github.com/ProjectEvergreen/greenwood/tree/master/packages/plugin-import-raw), you'll need to create a wrapping Vite plugin to handle this transformation. + + + + + + ```js + import { defineConfig } from "vitest/config"; + import fs from "node:fs/promises"; + import path from 'node:path'; + // 1) import the greenwood plugin and lifecycle helpers + import { greenwoodPluginImportRaw } from "@greenwood/plugin-import-raw"; + import { readAndMergeConfig } from "@greenwood/cli/src/lifecycles/config.js"; + import { initContext } from "@greenwood/cli/src/lifecycles/context.js"; + + // 2) initialize Greenwood lifecycles + const config = await readAndMergeConfig(); + const context = await initContext({ config }); + const compilation = { context, config }; + + // 3) initialize the plugin + const rawResource = greenwoodPluginImportRaw()[0].provider(compilation); + + // 4) customize Vite + function transformRawImports() { + const hint = "?type=raw"; + + return { + name: "transform-raw-imports", + enforce: "pre", + resolveId: (id, importer) => { + + if ( + id.endsWith(hint) + ) { + // append .type to the end of .css file paths so they are not automatically precessed by Vite's default CSS pipeline + return path.join(path.dirname(importer), `${id.slice(0, id.indexOf(hint))}.type${hint}`); + } + }, + load: async (id) => { + if (id.endsWith(hint)) { + const filename = id.slice(0, id.indexOf(`.type${hint}`)); + const contents = await fs.readFile(filename, "utf-8"); + const response = await rawResource.intercept(new URL(`file://${filename}`), null, new Response(contents)); + const body = await response.text(); + + return body; + } + }, + }; + } + + export default defineConfig({ + test: {/* ... */}, + + // 5) add it the plugins option + plugins: [transformRawImports()], + }); + ``` + + + + + +## Content as Data + +If you are using any of Greenwood's Content as Data [Client APIs](/docs/content-as-data/data-client/), you'll want to configure Vitest to mock the HTTP calls Greenwood's data client makes, and provide the desired response needed based on the API being called. + +We'll also need to use Vitest's [`waitUntil` utility](https://vitest.dev/api/vi.html#vi-waituntil) to handle any usage of `async connectedCallback` in your components. + + + + + + ```js + import { describe, it, expect, beforeEach, afterEach, vi, beforeAll, afterAll } from 'vitest'; + import pages from '../../../.greenwood/graph.json' with { type: 'json' }; + import './footer.js'; + + describe('Components/Footer', () => { + let footer; + + beforeAll(() => { + // mock fetch + window.fetch = vi.fn(() => { + return new Promise((resolve) => { + resolve( + new Response(JSON.stringify(pages.filter((page) => page.data.collection === 'nav'))), + ); + }); + }); + }); + + beforeEach(async () => { + footer = document.createElement('app-footer'); + + document.body.appendChild(footer); + + // to support async connected callback usage by waiting for a particular element to appear in the DOM + await vi.waitUntil(() => footer.querySelector('footer')); + }); + + describe('Default Behavior', () => { + it('should not be null', () => { + expect(footer).not.equal(undefined); + expect(footer.querySelectorAll('footer').length).equal(1); + }); + + // ... + }); + + afterEach(() => { + footer.remove(); + footer = undefined; + }); + + afterAll(() => { + vi.clearAllMocks(); + vi.resetAllMocks(); + }); + }); + ``` + + + + + +> To quickly get a "mock" graph to use in your stories, you can run `greenwood build` and copy the _graph.json_ file from the build output directory. From 204ede092a71da749a13b4984cfd9b74d7b25822 Mon Sep 17 00:00:00 2001 From: Owen Buckley Date: Fri, 13 Feb 2026 20:30:50 -0500 Subject: [PATCH 3/7] docs: de-duplicate vite specific configurations from storybook guide --- src/pages/guides/ecosystem/storybook.md | 143 +----------------------- 1 file changed, 2 insertions(+), 141 deletions(-) diff --git a/src/pages/guides/ecosystem/storybook.md b/src/pages/guides/ecosystem/storybook.md index 4d301a7d..a927caa0 100644 --- a/src/pages/guides/ecosystem/storybook.md +++ b/src/pages/guides/ecosystem/storybook.md @@ -47,6 +47,8 @@ We were not able to detect the right builder for your project. Please select one Webpack 5 ``` +> See our Vitest docs to see additional configuration examples for [Import Attributes](/guides/ecosystem/vitest/#import-attributes) and [Greenwood resource plugins](/guides/ecosystem/vitest/#resource-plugins); updating your _vite.config.js_ file instead. + ## Usage You should now be good to start writing your first story! 📚 @@ -145,147 +147,6 @@ You'll want to create a CommonJS version with the following name, depending on w -## Import Attributes - -As [Vite does not support Import Attributes](https://github.com/vitejs/vite/issues/14674), we will need to create a _vite.config.js_ and write a [custom plugin](https://vitejs.dev/guide/api-plugin) to work around this. - -In this example we are handling for CSS Module scripts: - - - - - - ```js - import { defineConfig } from "vite"; - import fs from "node:fs/promises"; - import path from "node:path"; - // 1) import the greenwood plugin and lifecycle helpers - import { greenwoodPluginStandardCss } from "@greenwood/cli/src/plugins/resource/plugin-standard-css.js"; - import { readAndMergeConfig } from "@greenwood/cli/src/lifecycles/config.js"; - import { initContext } from "@greenwood/cli/src/lifecycles/context.js"; - - // 2) initialize Greenwood lifecycles - const config = await readAndMergeConfig(); - const context = await initContext({ config }); - const compilation = { context, config }; - - // 3) initialize the plugin - const standardCssResource = greenwoodPluginStandardCss.provider(compilation); - - // 4) customize Vite - function transformConstructableStylesheetsPlugin() { - return { - name: "transform-constructable-stylesheets", - enforce: "pre", - resolveId: (id, importer) => { - if ( - // you'll need to configure this `importer` line to the location of your own components - importer?.indexOf("/src/components/") >= 0 && - id.endsWith(".css") && - !id.endsWith(".module.css") - ) { - // append .type to the end of Constructable Stylesheet file paths so that they are not automatically precessed by Vite's default pipeline - return path.join(path.dirname(importer), `${id}.type`); - } - }, - load: async (id) => { - if (id.endsWith(".css.type")) { - const filename = id.slice(0, -5); - const contents = await fs.readFile(filename, "utf-8"); - const url = new URL(`file://${id.replace(".type", "")}`); - // "coerce" native constructable stylesheets into inline JS so Vite / Rollup do not complain - const request = new Request(url, { - headers: { - Accept: "text/javascript", - }, - }); - const response = await standardCssResource.intercept(url, request, new Response(contents)); - const body = await response.text(); - - return body; - } - }, - }; - } - - export default defineConfig({ - // 5) add it the plugins option - plugins: [transformConstructableStylesheetsPlugin()], - }); - ``` - - - - - -Phew, should be all set now. - -## Resource Plugins - -If you're using one of Greenwood's [resource plugins](/docs/plugins/), you'll need a _vite.config.js_ so we can create a custom transformation plugin that can leverage Greenwood's plugins to automatically handle custom transformations. - -For example, if you're using Greenwood's [Raw Plugin](https://github.com/ProjectEvergreen/greenwood/tree/master/packages/plugin-import-raw), you'll need to create a wrapping Vite plugin to handle this transformation. - - - - - - ```js - import { defineConfig } from "vite"; - import fs from "node:fs/promises"; - import path from 'node:path'; - // 1) import the greenwood plugin and lifecycle helpers - import { greenwoodPluginImportRaw } from "@greenwood/plugin-import-raw"; - import { readAndMergeConfig } from "@greenwood/cli/src/lifecycles/config.js"; - import { initContext } from "@greenwood/cli/src/lifecycles/context.js"; - - // 2) initialize Greenwood lifecycles - const config = await readAndMergeConfig(); - const context = await initContext({ config }); - const compilation = { context, config }; - - // 3) initialize the plugin - const rawResource = greenwoodPluginImportRaw()[0].provider(compilation); - - // 4) customize Vite - function transformRawImports() { - const hint = "?type=raw"; - - return { - name: "transform-raw-imports", - enforce: "pre", - resolveId: (id, importer) => { - - if ( - id.endsWith(hint) - ) { - // append .type to the end of .css file paths so they are not automatically precessed by Vite's default CSS pipeline - return path.join(path.dirname(importer), `${id.slice(0, id.indexOf(hint))}.type${hint}`); - } - }, - load: async (id) => { - if (id.endsWith(hint)) { - const filename = id.slice(0, id.indexOf(`.type${hint}`)); - const contents = await fs.readFile(filename, "utf-8"); - const response = await rawResource.intercept(new URL(`file://${filename}`), null, new Response(contents)); - const body = await response.text(); - - return body; - } - }, - }; - } - - export default defineConfig({ - // 5) add it the plugins option - plugins: [transformRawImports()], - }); - ``` - - - - - ## Content as Data If you are using any of Greenwood's Content as Data [Client APIs](/docs/content-as-data/data-client/), you'll want to configure Storybook to mock the HTTP calls Greenwood's data client makes, and provide the desired response needed based on the API being called. From ee16bd1ebb3656fabfd1b3e319c8a7358fd77009 Mon Sep 17 00:00:00 2001 From: Owen Buckley Date: Fri, 13 Feb 2026 20:45:46 -0500 Subject: [PATCH 4/7] docs: grammar --- src/pages/guides/ecosystem/storybook.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/guides/ecosystem/storybook.md b/src/pages/guides/ecosystem/storybook.md index a927caa0..39d0dc02 100644 --- a/src/pages/guides/ecosystem/storybook.md +++ b/src/pages/guides/ecosystem/storybook.md @@ -47,7 +47,7 @@ We were not able to detect the right builder for your project. Please select one Webpack 5 ``` -> See our Vitest docs to see additional configuration examples for [Import Attributes](/guides/ecosystem/vitest/#import-attributes) and [Greenwood resource plugins](/guides/ecosystem/vitest/#resource-plugins); updating your _vite.config.js_ file instead. +> See our Vitest docs for additional configuration examples for [Import Attributes](/guides/ecosystem/vitest/#import-attributes) and [Greenwood resource plugins](/guides/ecosystem/vitest/#resource-plugins); updating your _vite.config.js_ file instead. ## Usage From 93eb733192ce1061a787f70d225e763e3660b417 Mon Sep 17 00:00:00 2001 From: Owen Buckley Date: Fri, 13 Feb 2026 20:49:24 -0500 Subject: [PATCH 5/7] docs: grammar --- src/pages/guides/ecosystem/storybook.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/pages/guides/ecosystem/storybook.md b/src/pages/guides/ecosystem/storybook.md index 39d0dc02..4c3bc432 100644 --- a/src/pages/guides/ecosystem/storybook.md +++ b/src/pages/guides/ecosystem/storybook.md @@ -47,7 +47,7 @@ We were not able to detect the right builder for your project. Please select one Webpack 5 ``` -> See our Vitest docs for additional configuration examples for [Import Attributes](/guides/ecosystem/vitest/#import-attributes) and [Greenwood resource plugins](/guides/ecosystem/vitest/#resource-plugins); updating your _vite.config.js_ file instead. +> See our Vitest docs for additional configuration examples to support [Import Attributes](/guides/ecosystem/vitest/#import-attributes) and [Greenwood resource plugins](/guides/ecosystem/vitest/#resource-plugins) usage in your components. For this guide, you'll be updating a _vite.config.js_ file instead. ## Usage From ffb9928f1a818c5f82ffa1d8aa17b11535b8c603 Mon Sep 17 00:00:00 2001 From: Owen Buckley Date: Wed, 18 Feb 2026 22:26:54 -0500 Subject: [PATCH 6/7] docs: vitest docs final drafting and home page logo tweaks and labels --- src/assets/vitest.svg | 2 +- .../build-with-friends/build-with-friends.js | 10 ++++++---- .../build-with-friends.module.css | 4 ++++ src/pages/guides/ecosystem/storybook.md | 2 +- src/pages/guides/ecosystem/vitest.md | 16 ++++++++-------- 5 files changed, 20 insertions(+), 14 deletions(-) diff --git a/src/assets/vitest.svg b/src/assets/vitest.svg index d230a3b6..f5baed5d 100644 --- a/src/assets/vitest.svg +++ b/src/assets/vitest.svg @@ -1,4 +1,4 @@ - + diff --git a/src/components/build-with-friends/build-with-friends.js b/src/components/build-with-friends/build-with-friends.js index 783344d1..d64a7bcf 100644 --- a/src/components/build-with-friends/build-with-friends.js +++ b/src/components/build-with-friends/build-with-friends.js @@ -35,17 +35,19 @@ export default class BuildWithFriends extends HTMLElement { ${wtrIcon} - Web Test Runner + Web Test Runner - ${wccIcon} + ${wccIcon} + WC Compiler ${openPropsIcon} - Open Props + Open Props - ${vitestIcon} + ${vitestIcon} + Vitest diff --git a/src/components/build-with-friends/build-with-friends.module.css b/src/components/build-with-friends/build-with-friends.module.css index 1c876e00..a8d8706b 100644 --- a/src/components/build-with-friends/build-with-friends.module.css +++ b/src/components/build-with-friends/build-with-friends.module.css @@ -35,6 +35,10 @@ display: inline-block; } +.iconLabel { + padding-left: var(--size-1); +} + @media (min-width: 600px) { .icon { display: inline-block; diff --git a/src/pages/guides/ecosystem/storybook.md b/src/pages/guides/ecosystem/storybook.md index 4c3bc432..ade796ca 100644 --- a/src/pages/guides/ecosystem/storybook.md +++ b/src/pages/guides/ecosystem/storybook.md @@ -47,7 +47,7 @@ We were not able to detect the right builder for your project. Please select one Webpack 5 ``` -> See our Vitest docs for additional configuration examples to support [Import Attributes](/guides/ecosystem/vitest/#import-attributes) and [Greenwood resource plugins](/guides/ecosystem/vitest/#resource-plugins) usage in your components. For this guide, you'll be updating a _vite.config.js_ file instead. +> See our Vitest docs for additional configuration examples to support [Import Attributes](/guides/ecosystem/vitest/#import-attributes) and [Greenwood resource plugins](/guides/ecosystem/vitest/#resource-plugins) usage in your components. For that guide, you'll be updating a _vite.config.js_ file instead. ## Usage diff --git a/src/pages/guides/ecosystem/vitest.md b/src/pages/guides/ecosystem/vitest.md index a173b262..81c63d35 100644 --- a/src/pages/guides/ecosystem/vitest.md +++ b/src/pages/guides/ecosystem/vitest.md @@ -14,7 +14,7 @@ tocHeading: 2 > At time of writing, this guide was based on Vitest v4.x and Vite v7.x. -Install Vite and Vitest: +First, install Vite and Vitest: @@ -56,13 +56,13 @@ Next, let's create a _vitest.config.js_ file and configure the location of our t -Lastly, let's create some NPM scripts to run our tests. By default, vitest will run in watch mode which is great for TDD (Test Driven Development). +Lastly, let's create some NPM scripts to run your tests. By default, Vitest will run in watch mode which is great for TDD (Test Driven Development). -Below is an example of how to setup NPM scripts for development: +Below is an example of how to setup NPM scripts for testing: - + ```json { @@ -99,7 +99,7 @@ The best way to test Web Components is in a browser. For this guide, we will use -Then install Playwright +Then install Playwright: @@ -141,7 +141,7 @@ Then in our _vitest.config.js_ file, let's add configuration for Playwright: -> Note: For CI environments like GitHub Actions, you'll want to add a step for install Playwright include deps +> Note: For CI environments like GitHub Actions, you'll want to add a step for installing Playwright, including the [`--with-deps` flag](https://playwright.dev/docs/ci): > > ```shell > npx playwright install --with-deps @@ -225,7 +225,7 @@ You should now be good to start writing your first test! ⚡ ## Import Attributes -As [Vite does not support Import Attributes](https://github.com/vitejs/vite/issues/14674), we will need to update our _vitest.config.js_ file and write a [custom plugin](https://vitejs.dev/guide/api-plugin) to work around this. +As [Vite does not support Import Attributes](https://github.com/vitejs/vite/issues/14674), you will need to update your _vitest.config.js_ file and write a [custom plugin](https://vitejs.dev/guide/api-plugin) to work around this. In this example we are handling for CSS Module scripts: @@ -302,7 +302,7 @@ Phew, should be all set now. ## Resource Plugins -If you're using one of Greenwood's [resource plugins](/docs/plugins/), you'll want to update the _vitest.config.js_ file so we can create a custom transformation plugin that can leverage Greenwood's plugins to automatically handle custom transformations. +If you're using one of Greenwood's [resource plugins](/docs/plugins/), you'll want to update the _vitest.config.js_ file with a plugin that can leverage Greenwood's plugins to automatically handle custom transformations. For example, if you're using Greenwood's [Raw Plugin](https://github.com/ProjectEvergreen/greenwood/tree/master/packages/plugin-import-raw), you'll need to create a wrapping Vite plugin to handle this transformation. From fcfe1d8ddcf324b3cc8afca43629150dc6581cf4 Mon Sep 17 00:00:00 2001 From: Owen Buckley Date: Wed, 18 Feb 2026 22:29:49 -0500 Subject: [PATCH 7/7] docs: formatting --- src/pages/guides/ecosystem/vitest.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pages/guides/ecosystem/vitest.md b/src/pages/guides/ecosystem/vitest.md index 81c63d35..4518b83b 100644 --- a/src/pages/guides/ecosystem/vitest.md +++ b/src/pages/guides/ecosystem/vitest.md @@ -335,7 +335,6 @@ For example, if you're using Greenwood's [Raw Plugin](https://github.com/Project name: "transform-raw-imports", enforce: "pre", resolveId: (id, importer) => { - if ( id.endsWith(hint) ) {