Repository: ota-meshi/eslint-plugin-astro
Pull request #360 (2024-04-26 06:47:44)

feat!: use bundler

changeset-bot[bot]: ###  ⚠️  No Changeset found

Latest commit: 476bb17dc99d4087320a34f255b73830430979f7

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. **If these changes should result in a version bump, you need to add a changeset.**

<details><summary>This PR includes no changesets</summary>

  When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

</details>

[Click here to learn what changesets are, and how to add one](https://github.com/changesets/changesets/blob/main/docs/adding-a-changeset.md).

[Click here if you're a maintainer who wants to add a changeset to this PR](https://github.com/ota-meshi/eslint-plugin-astro/new/tsup?filename=.changeset/proud-poems-grin.md&value=---%0A%22eslint-plugin-astro%22%3A%20patch%0A---%0A%0Afeat!%3A%20use%20bundler%0A)



Patch:
diff --git a/.changeset/proud-poems-grin.md b/.changeset/proud-poems-grin.md
new file mode 100644
index 0000000..b61e65a
--- /dev/null
+++ b/.changeset/proud-poems-grin.md
@@ -0,0 +1,5 @@
+---
+"eslint-plugin-astro": major
+---
+
+feat!: use bundler
diff --git a/README.md b/README.md
index e3f6538..c62cc00 100644
--- a/README.md
+++ b/README.md
@@ -91,7 +91,24 @@ import eslintPluginAstro from 'eslint-plugin-astro';
 export default [
   // add more generic rule sets here, such as:
   // js.configs.recommended,
-  ...eslintPluginAstro.configs['flat/recommended'],
+  ...eslintPluginAstro.configs.recommended,
+  {
+    rules: {
+      // override/add rules settings here, such as:
+      // "astro/no-set-html-directive": "error"
+    }
+  }
+];
+```
+
+Example **eslint.config.cjs**:
+
+```js
+const eslintPluginAstro = require('eslint-plugin-astro');
+module.exports = [
+  // add more generic rule sets here, such as:
+  // js.configs.recommended,
+  ...eslintPluginAstro.configs['flat/recommended'], // In CommonJS, the `flat/` prefix is required.
   {
     rules: {
       // override/add rules settings here, such as:
@@ -103,12 +120,12 @@ export default [
 
 This plugin provides configs:
 
-- `*.configs['flat/base']` ... Minimal configuration to enable correct Astro component linting.
-- `*.configs['flat/recommended']` ... Above, plus rules to prevent errors or unintended behavior.
-- `*.configs['flat/all']` ... Configuration enables all astro rules. It's meant for testing, not for production use because it changes with every minor and major version of the plugin. Use it at your own risk.
+- `*.configs['base']` ... Minimal configuration to enable correct Astro component linting.
+- `*.configs['recommended']` ... Above, plus rules to prevent errors or unintended behavior.
+- `*.configs['all']` ... Configuration enables all astro rules. It's meant for testing, not for production use because it changes with every minor and major version of the plugin. Use it at your own risk.
 - Extension of sharable configuration provided by [eslint-plugin-jsx-a11y]. You need to install [eslint-plugin-jsx-a11y] to use it.
-  - `*.configs['flat/jsx-a11y-recommended']` ... Similar to the [`"plugin:jsx-a11y/recommended"` configuration](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#rule-strictness-in-different-modes), but with the rules extended for Astro components enabled.
-  - `*.configs['flat/jsx-a11y-strict']` ... Similar to the [`"plugin:jsx-a11y/strict"` configuration](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#rule-strictness-in-different-modes), but with the rules extended for Astro components enabled.
+  - `*.configs['jsx-a11y-recommended']` ... Similar to the [`"plugin:jsx-a11y/recommended"` configuration](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#rule-strictness-in-different-modes), but with the rules extended for Astro components enabled.
+  - `*.configs['jsx-a11y-strict']` ... Similar to the [`"plugin:jsx-a11y/strict"` configuration](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#rule-strictness-in-different-modes), but with the rules extended for Astro components enabled.
 
 See [the rule list](https://ota-meshi.github.io/eslint-plugin-astro/rules/) to get the `rules` that this plugin provides.
 
@@ -375,95 +392,95 @@ The rules with the following star ⭐ are included in the `plugin:astro/recommen
 
 These rules relate to possible syntax or logic errors in Astro component code:
 
-| Rule ID                                                                                                                                 | Description                                                                  |      |
-| :-------------------------------------------------------------------------------------------------------------------------------------- | :--------------------------------------------------------------------------- | :--- |
-| [astro/missing-client-only-directive-value](https://ota-meshi.github.io/eslint-plugin-astro/rules/missing-client-only-directive-value/) | the client:only directive is missing the correct component's framework value | ⭐    |
-| [astro/no-conflict-set-directives](https://ota-meshi.github.io/eslint-plugin-astro/rules/no-conflict-set-directives/)                   | disallow conflicting set directives and child contents                       | ⭐    |
-| [astro/no-deprecated-astro-canonicalurl](https://ota-meshi.github.io/eslint-plugin-astro/rules/no-deprecated-astro-canonicalurl/)       | disallow using deprecated `Astro.canonicalURL`                               | ⭐    |
-| [astro/no-deprecated-astro-fetchcontent](https://ota-meshi.github.io/eslint-plugin-astro/rules/no-deprecated-astro-fetchcontent/)       | disallow using deprecated `Astro.fetchContent()`                             | ⭐🔧   |
-| [astro/no-deprecated-astro-resolve](https://ota-meshi.github.io/eslint-plugin-astro/rules/no-deprecated-astro-resolve/)                 | disallow using deprecated `Astro.resolve()`                                  | ⭐    |
-| [astro/no-deprecated-getentrybyslug](https://ota-meshi.github.io/eslint-plugin-astro/rules/no-deprecated-getentrybyslug/)               | disallow using deprecated `getEntryBySlug()`                                 | ⭐    |
-| [astro/no-unused-define-vars-in-style](https://ota-meshi.github.io/eslint-plugin-astro/rules/no-unused-define-vars-in-style/)           | disallow unused `define:vars={...}` in `style` tag                           | ⭐    |
-| [astro/valid-compile](https://ota-meshi.github.io/eslint-plugin-astro/rules/valid-compile/)                                             | disallow warnings when compiling.                                            | ⭐    |
+| Rule ID | Description |    |
+|:--------|:------------|:---|
+| [astro/missing-client-only-directive-value](https://ota-meshi.github.io/eslint-plugin-astro/rules/missing-client-only-directive-value/) | the client:only directive is missing the correct component's framework value | ⭐ |
+| [astro/no-conflict-set-directives](https://ota-meshi.github.io/eslint-plugin-astro/rules/no-conflict-set-directives/) | disallow conflicting set directives and child contents | ⭐ |
+| [astro/no-deprecated-astro-canonicalurl](https://ota-meshi.github.io/eslint-plugin-astro/rules/no-deprecated-astro-canonicalurl/) | disallow using deprecated `Astro.canonicalURL` | ⭐ |
+| [astro/no-deprecated-astro-fetchcontent](https://ota-meshi.github.io/eslint-plugin-astro/rules/no-deprecated-astro-fetchcontent/) | disallow using deprecated `Astro.fetchContent()` | ⭐🔧 |
+| [astro/no-deprecated-astro-resolve](https://ota-meshi.github.io/eslint-plugin-astro/rules/no-deprecated-astro-resolve/) | disallow using deprecated `Astro.resolve()` | ⭐ |
+| [astro/no-deprecated-getentrybyslug](https://ota-meshi.github.io/eslint-plugin-astro/rules/no-deprecated-getentrybyslug/) | disallow using deprecated `getEntryBySlug()` | ⭐ |
+| [astro/no-unused-define-vars-in-style](https://ota-meshi.github.io/eslint-plugin-astro/rules/no-unused-define-vars-in-style/) | disallow unused `define:vars={...}` in `style` tag | ⭐ |
+| [astro/valid-compile](https://ota-meshi.github.io/eslint-plugin-astro/rules/valid-compile/) | disallow warnings when compiling. | ⭐ |
 
 ## Security Vulnerability
 
 These rules relate to security vulnerabilities in Astro component code:
 
-| Rule ID                                                                                                     | Description                                      |      |
-| :---------------------------------------------------------------------------------------------------------- | :----------------------------------------------- | :--- |
-| [astro/no-set-html-directive](https://ota-meshi.github.io/eslint-plugin-astro/rules/no-set-html-directive/) | disallow use of `set:html` to prevent XSS attack |      |
+| Rule ID | Description |    |
+|:--------|:------------|:---|
+| [astro/no-set-html-directive](https://ota-meshi.github.io/eslint-plugin-astro/rules/no-set-html-directive/) | disallow use of `set:html` to prevent XSS attack |  |
 
 ## Best Practices
 
 These rules relate to better ways of doing things to help you avoid problems:
 
-| Rule ID                                                                                                       | Description                                                      |      |
-| :------------------------------------------------------------------------------------------------------------ | :--------------------------------------------------------------- | :--- |
-| [astro/no-set-text-directive](https://ota-meshi.github.io/eslint-plugin-astro/rules/no-set-text-directive/)   | disallow use of `set:text`                                       | 🔧    |
-| [astro/no-unused-css-selector](https://ota-meshi.github.io/eslint-plugin-astro/rules/no-unused-css-selector/) | disallow selectors defined in `style` tag that don't use in HTML |      |
+| Rule ID | Description |    |
+|:--------|:------------|:---|
+| [astro/no-set-text-directive](https://ota-meshi.github.io/eslint-plugin-astro/rules/no-set-text-directive/) | disallow use of `set:text` | 🔧 |
+| [astro/no-unused-css-selector](https://ota-meshi.github.io/eslint-plugin-astro/rules/no-unused-css-selector/) | disallow selectors defined in `style` tag that don't use in HTML |  |
 
 ## Stylistic Issues
 
 These rules relate to style guidelines, and are therefore quite subjective:
 
-| Rule ID                                                                                                                 | Description                                                         |      |
-| :---------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------ | :--- |
-| [astro/prefer-class-list-directive](https://ota-meshi.github.io/eslint-plugin-astro/rules/prefer-class-list-directive/) | require `class:list` directives instead of `class` with expressions | 🔧    |
-| [astro/prefer-object-class-list](https://ota-meshi.github.io/eslint-plugin-astro/rules/prefer-object-class-list/)       | require use object instead of ternary expression in `class:list`    | 🔧    |
-| [astro/prefer-split-class-list](https://ota-meshi.github.io/eslint-plugin-astro/rules/prefer-split-class-list/)         | require use split array elements in `class:list`                    | 🔧    |
+| Rule ID | Description |    |
+|:--------|:------------|:---|
+| [astro/prefer-class-list-directive](https://ota-meshi.github.io/eslint-plugin-astro/rules/prefer-class-list-directive/) | require `class:list` directives instead of `class` with expressions | 🔧 |
+| [astro/prefer-object-class-list](https://ota-meshi.github.io/eslint-plugin-astro/rules/prefer-object-class-list/) | require use object instead of ternary expression in `class:list` | 🔧 |
+| [astro/prefer-split-class-list](https://ota-meshi.github.io/eslint-plugin-astro/rules/prefer-split-class-list/) | require use split array elements in `class:list` | 🔧 |
 
 ## A11Y Extension Rules
 
 These rules extend the rules provided by [eslint-plugin-jsx-a11y] to work well in Astro component:  
 (You need to install [eslint-plugin-jsx-a11y] to use the rules.)
 
-| Rule ID                                                                                                                                                                       | Description                                                                             |      |
-| :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------- | :--- |
-| [astro/jsx-a11y/alt-text](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/alt-text/)                                                                           | apply `jsx-a11y/alt-text` rule to Astro components                                      |      |
-| [astro/jsx-a11y/anchor-ambiguous-text](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/anchor-ambiguous-text/)                                                 | apply `jsx-a11y/anchor-ambiguous-text` rule to Astro components                         |      |
-| [astro/jsx-a11y/anchor-has-content](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/anchor-has-content/)                                                       | apply `jsx-a11y/anchor-has-content` rule to Astro components                            |      |
-| [astro/jsx-a11y/anchor-is-valid](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/anchor-is-valid/)                                                             | apply `jsx-a11y/anchor-is-valid` rule to Astro components                               |      |
-| [astro/jsx-a11y/aria-activedescendant-has-tabindex](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-activedescendant-has-tabindex/)                       | apply `jsx-a11y/aria-activedescendant-has-tabindex` rule to Astro components            |      |
-| [astro/jsx-a11y/aria-props](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-props/)                                                                       | apply `jsx-a11y/aria-props` rule to Astro components                                    |      |
-| [astro/jsx-a11y/aria-proptypes](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-proptypes/)                                                               | apply `jsx-a11y/aria-proptypes` rule to Astro components                                |      |
-| [astro/jsx-a11y/aria-role](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-role/)                                                                         | apply `jsx-a11y/aria-role` rule to Astro components                                     |      |
-| [astro/jsx-a11y/aria-unsupported-elements](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-unsupported-elements/)                                         | apply `jsx-a11y/aria-unsupported-elements` rule to Astro components                     |      |
-| [astro/jsx-a11y/autocomplete-valid](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/autocomplete-valid/)                                                       | apply `jsx-a11y/autocomplete-valid` rule to Astro components                            |      |
-| [astro/jsx-a11y/click-events-have-key-events](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/click-events-have-key-events/)                                   | apply `jsx-a11y/click-events-have-key-events` rule to Astro components                  |      |
-| [astro/jsx-a11y/control-has-associated-label](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/control-has-associated-label/)                                   | apply `jsx-a11y/control-has-associated-label` rule to Astro components                  |      |
-| [astro/jsx-a11y/heading-has-content](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/heading-has-content/)                                                     | apply `jsx-a11y/heading-has-content` rule to Astro components                           |      |
-| [astro/jsx-a11y/html-has-lang](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/html-has-lang/)                                                                 | apply `jsx-a11y/html-has-lang` rule to Astro components                                 |      |
-| [astro/jsx-a11y/iframe-has-title](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/iframe-has-title/)                                                           | apply `jsx-a11y/iframe-has-title` rule to Astro components                              |      |
-| [astro/jsx-a11y/img-redundant-alt](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/img-redundant-alt/)                                                         | apply `jsx-a11y/img-redundant-alt` rule to Astro components                             |      |
-| [astro/jsx-a11y/interactive-supports-focus](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/interactive-supports-focus/)                                       | apply `jsx-a11y/interactive-supports-focus` rule to Astro components                    |      |
-| [astro/jsx-a11y/label-has-associated-control](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/label-has-associated-control/)                                   | apply `jsx-a11y/label-has-associated-control` rule to Astro components                  |      |
-| [astro/jsx-a11y/lang](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/lang/)                                                                                   | apply `jsx-a11y/lang` rule to Astro components                                          |      |
-| [astro/jsx-a11y/media-has-caption](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/media-has-caption/)                                                         | apply `jsx-a11y/media-has-caption` rule to Astro components                             |      |
-| [astro/jsx-a11y/mouse-events-have-key-events](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/mouse-events-have-key-events/)                                   | apply `jsx-a11y/mouse-events-have-key-events` rule to Astro components                  |      |
-| [astro/jsx-a11y/no-access-key](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-access-key/)                                                                 | apply `jsx-a11y/no-access-key` rule to Astro components                                 |      |
-| [astro/jsx-a11y/no-aria-hidden-on-focusable](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-aria-hidden-on-focusable/)                                     | apply `jsx-a11y/no-aria-hidden-on-focusable` rule to Astro components                   |      |
-| [astro/jsx-a11y/no-autofocus](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-autofocus/)                                                                   | apply `jsx-a11y/no-autofocus` rule to Astro components                                  |      |
-| [astro/jsx-a11y/no-distracting-elements](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-distracting-elements/)                                             | apply `jsx-a11y/no-distracting-elements` rule to Astro components                       |      |
-| [astro/jsx-a11y/no-interactive-element-to-noninteractive-role](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-interactive-element-to-noninteractive-role/) | apply `jsx-a11y/no-interactive-element-to-noninteractive-role` rule to Astro components |      |
-| [astro/jsx-a11y/no-noninteractive-element-interactions](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-noninteractive-element-interactions/)               | apply `jsx-a11y/no-noninteractive-element-interactions` rule to Astro components        |      |
-| [astro/jsx-a11y/no-noninteractive-element-to-interactive-role](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-noninteractive-element-to-interactive-role/) | apply `jsx-a11y/no-noninteractive-element-to-interactive-role` rule to Astro components |      |
-| [astro/jsx-a11y/no-noninteractive-tabindex](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-noninteractive-tabindex/)                                       | apply `jsx-a11y/no-noninteractive-tabindex` rule to Astro components                    |      |
-| [astro/jsx-a11y/no-redundant-roles](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-redundant-roles/)                                                       | apply `jsx-a11y/no-redundant-roles` rule to Astro components                            |      |
-| [astro/jsx-a11y/no-static-element-interactions](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-static-element-interactions/)                               | apply `jsx-a11y/no-static-element-interactions` rule to Astro components                |      |
-| [astro/jsx-a11y/prefer-tag-over-role](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/prefer-tag-over-role/)                                                   | apply `jsx-a11y/prefer-tag-over-role` rule to Astro components                          |      |
-| [astro/jsx-a11y/role-has-required-aria-props](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/role-has-required-aria-props/)                                   | apply `jsx-a11y/role-has-required-aria-props` rule to Astro components                  |      |
-| [astro/jsx-a11y/role-supports-aria-props](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/role-supports-aria-props/)                                           | apply `jsx-a11y/role-supports-aria-props` rule to Astro components                      |      |
-| [astro/jsx-a11y/scope](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/scope/)                                                                                 | apply `jsx-a11y/scope` rule to Astro components                                         |      |
-| [astro/jsx-a11y/tabindex-no-positive](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/tabindex-no-positive/)                                                   | apply `jsx-a11y/tabindex-no-positive` rule to Astro components                          |      |
+| Rule ID | Description |    |
+|:--------|:------------|:---|
+| [astro/jsx-a11y/alt-text](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/alt-text/) | apply `jsx-a11y/alt-text` rule to Astro components |  |
+| [astro/jsx-a11y/anchor-ambiguous-text](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/anchor-ambiguous-text/) | apply `jsx-a11y/anchor-ambiguous-text` rule to Astro components |  |
+| [astro/jsx-a11y/anchor-has-content](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/anchor-has-content/) | apply `jsx-a11y/anchor-has-content` rule to Astro components |  |
+| [astro/jsx-a11y/anchor-is-valid](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/anchor-is-valid/) | apply `jsx-a11y/anchor-is-valid` rule to Astro components |  |
+| [astro/jsx-a11y/aria-activedescendant-has-tabindex](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-activedescendant-has-tabindex/) | apply `jsx-a11y/aria-activedescendant-has-tabindex` rule to Astro components |  |
+| [astro/jsx-a11y/aria-props](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-props/) | apply `jsx-a11y/aria-props` rule to Astro components |  |
+| [astro/jsx-a11y/aria-proptypes](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-proptypes/) | apply `jsx-a11y/aria-proptypes` rule to Astro components |  |
+| [astro/jsx-a11y/aria-role](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-role/) | apply `jsx-a11y/aria-role` rule to Astro components |  |
+| [astro/jsx-a11y/aria-unsupported-elements](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/aria-unsupported-elements/) | apply `jsx-a11y/aria-unsupported-elements` rule to Astro components |  |
+| [astro/jsx-a11y/autocomplete-valid](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/autocomplete-valid/) | apply `jsx-a11y/autocomplete-valid` rule to Astro components |  |
+| [astro/jsx-a11y/click-events-have-key-events](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/click-events-have-key-events/) | apply `jsx-a11y/click-events-have-key-events` rule to Astro components |  |
+| [astro/jsx-a11y/control-has-associated-label](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/control-has-associated-label/) | apply `jsx-a11y/control-has-associated-label` rule to Astro components |  |
+| [astro/jsx-a11y/heading-has-content](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/heading-has-content/) | apply `jsx-a11y/heading-has-content` rule to Astro components |  |
+| [astro/jsx-a11y/html-has-lang](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/html-has-lang/) | apply `jsx-a11y/html-has-lang` rule to Astro components |  |
+| [astro/jsx-a11y/iframe-has-title](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/iframe-has-title/) | apply `jsx-a11y/iframe-has-title` rule to Astro components |  |
+| [astro/jsx-a11y/img-redundant-alt](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/img-redundant-alt/) | apply `jsx-a11y/img-redundant-alt` rule to Astro components |  |
+| [astro/jsx-a11y/interactive-supports-focus](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/interactive-supports-focus/) | apply `jsx-a11y/interactive-supports-focus` rule to Astro components |  |
+| [astro/jsx-a11y/label-has-associated-control](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/label-has-associated-control/) | apply `jsx-a11y/label-has-associated-control` rule to Astro components |  |
+| [astro/jsx-a11y/lang](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/lang/) | apply `jsx-a11y/lang` rule to Astro components |  |
+| [astro/jsx-a11y/media-has-caption](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/media-has-caption/) | apply `jsx-a11y/media-has-caption` rule to Astro components |  |
+| [astro/jsx-a11y/mouse-events-have-key-events](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/mouse-events-have-key-events/) | apply `jsx-a11y/mouse-events-have-key-events` rule to Astro components |  |
+| [astro/jsx-a11y/no-access-key](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-access-key/) | apply `jsx-a11y/no-access-key` rule to Astro components |  |
+| [astro/jsx-a11y/no-aria-hidden-on-focusable](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-aria-hidden-on-focusable/) | apply `jsx-a11y/no-aria-hidden-on-focusable` rule to Astro components |  |
+| [astro/jsx-a11y/no-autofocus](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-autofocus/) | apply `jsx-a11y/no-autofocus` rule to Astro components |  |
+| [astro/jsx-a11y/no-distracting-elements](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-distracting-elements/) | apply `jsx-a11y/no-distracting-elements` rule to Astro components |  |
+| [astro/jsx-a11y/no-interactive-element-to-noninteractive-role](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-interactive-element-to-noninteractive-role/) | apply `jsx-a11y/no-interactive-element-to-noninteractive-role` rule to Astro components |  |
+| [astro/jsx-a11y/no-noninteractive-element-interactions](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-noninteractive-element-interactions/) | apply `jsx-a11y/no-noninteractive-element-interactions` rule to Astro components |  |
+| [astro/jsx-a11y/no-noninteractive-element-to-interactive-role](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-noninteractive-element-to-interactive-role/) | apply `jsx-a11y/no-noninteractive-element-to-interactive-role` rule to Astro components |  |
+| [astro/jsx-a11y/no-noninteractive-tabindex](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-noninteractive-tabindex/) | apply `jsx-a11y/no-noninteractive-tabindex` rule to Astro components |  |
+| [astro/jsx-a11y/no-redundant-roles](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-redundant-roles/) | apply `jsx-a11y/no-redundant-roles` rule to Astro components |  |
+| [astro/jsx-a11y/no-static-element-interactions](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/no-static-element-interactions/) | apply `jsx-a11y/no-static-element-interactions` rule to Astro components |  |
+| [astro/jsx-a11y/prefer-tag-over-role](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/prefer-tag-over-role/) | apply `jsx-a11y/prefer-tag-over-role` rule to Astro components |  |
+| [astro/jsx-a11y/role-has-required-aria-props](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/role-has-required-aria-props/) | apply `jsx-a11y/role-has-required-aria-props` rule to Astro components |  |
+| [astro/jsx-a11y/role-supports-aria-props](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/role-supports-aria-props/) | apply `jsx-a11y/role-supports-aria-props` rule to Astro components |  |
+| [astro/jsx-a11y/scope](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/scope/) | apply `jsx-a11y/scope` rule to Astro components |  |
+| [astro/jsx-a11y/tabindex-no-positive](https://ota-meshi.github.io/eslint-plugin-astro/rules/jsx-a11y/tabindex-no-positive/) | apply `jsx-a11y/tabindex-no-positive` rule to Astro components |  |
 
 ## Extension Rules
 
 These rules extend the rules provided by ESLint itself to work well in Astro component:
 
-| Rule ID                                                                   | Description                                   |      |
-| :------------------------------------------------------------------------ | :-------------------------------------------- | :--- |
-| [astro/semi](https://ota-meshi.github.io/eslint-plugin-astro/rules/semi/) | Require or disallow semicolons instead of ASI | 🔧    |
+| Rule ID | Description |    |
+|:--------|:------------|:---|
+| [astro/semi](https://ota-meshi.github.io/eslint-plugin-astro/rules/semi/) | Require or disallow semicolons instead of ASI | 🔧 |
 
 <!--RULES_TABLE_END-->
 <!--RULES_SECTION_END-->
diff --git a/docs-build/src/components/RightSidebar/MoreMenu.astro b/docs-build/src/components/RightSidebar/MoreMenu.astro
index f5fbf78..db2232c 100644
--- a/docs-build/src/components/RightSidebar/MoreMenu.astro
+++ b/docs-build/src/components/RightSidebar/MoreMenu.astro
@@ -11,7 +11,6 @@ const showMoreSection = CONFIG.COMMUNITY_INVITE_URL || editHref
     editHref && (
       <li class:list={[`header-link`, `depth-2`]}>
         <a class="edit-on-github" href={editHref} target="_blank">
-          {/* eslint-disable-next-line astro/jsx-a11y/prefer-tag-over-role -- how to fix it? */}
           <svg
             aria-hidden="true"
             focusable="false"
@@ -38,7 +37,6 @@ const showMoreSection = CONFIG.COMMUNITY_INVITE_URL || editHref
     CONFIG.COMMUNITY_INVITE_URL && (
       <li class:list={[`header-link`, `depth-2`]}>
         <a href={CONFIG.COMMUNITY_INVITE_URL} target="_blank">
-          {/* eslint-disable-next-line astro/jsx-a11y/prefer-tag-over-role -- how to fix it? */}
           <svg
             aria-hidden="true"
             focusable="false"
diff --git a/docs/user-guide.md b/docs/user-guide.md
index a4a208a..8374d54 100644
--- a/docs/user-guide.md
+++ b/docs/user-guide.md
@@ -47,7 +47,24 @@ import eslintPluginAstro from 'eslint-plugin-astro';
 export default [
   // add more generic rule sets here, such as:
   // js.configs.recommended,
-  ...eslintPluginAstro.configs['flat/recommended'],
+  ...eslintPluginAstro.configs.recommended,
+  {
+    rules: {
+      // override/add rules settings here, such as:
+      // "astro/no-set-html-directive": "error"
+    }
+  }
+];
+```
+
+Example **eslint.config.cjs**:
+
+```js
+const eslintPluginAstro = require('eslint-plugin-astro');
+module.exports = [
+  // add more generic rule sets here, such as:
+  // js.configs.recommended,
+  ...eslintPluginAstro.configs['flat/recommended'], // In CommonJS, the `flat/` prefix is required.
   {
     rules: {
       // override/add rules settings here, such as:
@@ -59,12 +76,12 @@ export default [
 
 This plugin provides configs:
 
-- `*.configs['flat/base']` ... Minimal configuration to enable correct Astro component linting.
-- `*.configs['flat/recommended']` ... Above, plus rules to prevent errors or unintended behavior.
-- `*.configs['flat/all']` ... Configuration enables all astro rules. It's meant for testing, not for production use because it changes with every minor and major version of the plugin. Use it at your own risk.
+- `*.configs['base']` ... Minimal configuration to enable correct Astro component linting.
+- `*.configs['recommended']` ... Above, plus rules to prevent errors or unintended behavior.
+- `*.configs['all']` ... Configuration enables all astro rules. It's meant for testing, not for production use because it changes with every minor and major version of the plugin. Use it at your own risk.
 - Extension of sharable configuration provided by [eslint-plugin-jsx-a11y]. You need to install [eslint-plugin-jsx-a11y] to use it.
-  - `*.configs['flat/jsx-a11y-recommended']` ... Similar to the [`"plugin:jsx-a11y/recommended"` configuration](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#rule-strictness-in-different-modes), but with the rules extended for Astro components enabled.
-  - `*.configs['flat/jsx-a11y-strict']` ... Similar to the [`"plugin:jsx-a11y/strict"` configuration](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#rule-strictness-in-different-modes), but with the rules extended for Astro components enabled.
+  - `*.configs['jsx-a11y-recommended']` ... Similar to the [`"plugin:jsx-a11y/recommended"` configuration](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#rule-strictness-in-different-modes), but with the rules extended for Astro components enabled.
+  - `*.configs['jsx-a11y-strict']` ... Similar to the [`"plugin:jsx-a11y/strict"` configuration](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y#rule-strictness-in-different-modes), but with the rules extended for Astro components enabled.
 
 See [the rule list](./rules.md) to get the `rules` that this plugin provides.
 
diff --git a/package.json b/package.json
index 313c231..faa71c4 100644
--- a/package.json
+++ b/package.json
@@ -2,7 +2,8 @@
   "name": "eslint-plugin-astro",
   "version": "0.34.0",
   "description": "ESLint plugin for Astro component",
-  "main": "lib/index.js",
+  "main": "lib/index.cjs",
+  "module": "lib/index.mjs",
   "files": [
     "lib"
   ],
@@ -11,9 +12,9 @@
   },
   "scripts": {
     "prebuild": "npm run -s clean",
-    "build": "npm run build:meta && npm run build:ts",
+    "build": "npm run build:meta && npm run build:tsup",
     "build:meta": "npm run ts -- ./tools/update-meta.ts",
-    "build:ts": "tsc --project ./tsconfig.build.json",
+    "build:tsup": "tsup",
     "clean": "rimraf lib .nyc_output dist coverage",
     "test": "npm run mocha -- \"tests/src/**/*.ts\" --reporter dot --timeout 60000 && npm run test:type",
     "test:type": "tsc --noEmit",
@@ -124,6 +125,7 @@
     "sass": "^1.52.2",
     "stylus": "^0.63.0",
     "svelte": "^4.0.0",
+    "tsup": "^8.0.2",
     "typescript": "~5.4.0",
     "typescript-eslint": "^7.5.0",
     "vite-plugin-eslint4b": "^0.4.0"
diff --git a/src/a11y/configs.ts b/src/a11y/configs.ts
index 3ead605..ae5209e 100644
--- a/src/a11y/configs.ts
+++ b/src/a11y/configs.ts
@@ -1,19 +1,15 @@
 import { getPluginJsxA11y } from "./load"
-import path from "path"
 import { a11yConfigKeys } from "./keys"
 import flatBase from "../configs/flat/base"
+import type { Linter } from "eslint"
 
 /** Build a11y configs */
-export function buildConfigs(): Record<string, unknown> {
-  const basePath = require.resolve("../configs/base")
-  const baseExtend =
-    path.extname(`${basePath}`) === ".ts" ? "plugin:astro/base" : basePath
-
-  const configs: Record<string, unknown> = {}
+export function buildFlatConfigs(): Record<string, Linter.FlatConfig[]> {
+  const configs: Record<string, Linter.FlatConfig[]> = {}
 
   for (const configName of a11yConfigKeys) {
     // flat config
-    Object.defineProperty(configs, `flat/jsx-a11y-${configName}`, {
+    Object.defineProperty(configs, `jsx-a11y-${configName}`, {
       enumerable: true,
       get() {
         const base = getPluginJsxA11y()
@@ -34,6 +30,17 @@ export function buildConfigs(): Record<string, unknown> {
         ]
       },
     })
+  }
+  return configs
+}
+
+/** Build a11y configs */
+export function buildLegacyConfigs(): Record<string, Linter.Config> {
+  const baseExtend = "plugin:astro/base"
+
+  const configs: Record<string, Linter.Config> = {}
+
+  for (const configName of a11yConfigKeys) {
     // legacy config
     Object.defineProperty(configs, `jsx-a11y-${configName}`, {
       enumerable: true,
diff --git a/src/a11y/index.ts b/src/a11y/index.ts
index 6f1f956..7e5b03b 100644
--- a/src/a11y/index.ts
+++ b/src/a11y/index.ts
@@ -1,5 +1,6 @@
+import type { Linter } from "eslint"
 import type { RuleModule } from "../types"
-import { buildConfigs } from "./configs"
+import { buildFlatConfigs, buildLegacyConfigs } from "./configs"
 import { buildRules } from "./rules"
 
 /** Build a11y rules */
@@ -8,6 +9,11 @@ export function buildA11yRules(): RuleModule[] {
 }
 
 /** Build a11y configs */
-export function buildA11yConfigs(): Record<string, unknown> {
-  return buildConfigs()
+export function buildA11yFlatConfigs(): Record<string, Linter.FlatConfig[]> {
+  return buildFlatConfigs()
+}
+
+/** Build a11y configs */
+export function buildA11yLegacyConfigs(): Record<string, Linter.Config> {
+  return buildLegacyConfigs()
 }
diff --git a/src/configs/all.ts b/src/configs/all.ts
index e4ab78d..0d1c76b 100644
--- a/src/configs/all.ts
+++ b/src/configs/all.ts
@@ -8,7 +8,7 @@ for (const rule of rules.filter(
   all[rule.meta.docs.ruleId] = "error"
 }
 
-export = {
+export default {
   extends: recommended.extends,
   rules: {
     ...all,
diff --git a/src/configs/base.ts b/src/configs/base.ts
index 8c26153..27de33e 100644
--- a/src/configs/base.ts
+++ b/src/configs/base.ts
@@ -3,7 +3,7 @@
 // in order to update its content execute "npm run update"
 import { hasTypescriptEslintParser } from "./has-typescript-eslint-parser"
 
-export = {
+export default {
   plugins: ["astro"],
   overrides: [
     {
diff --git a/src/configs/flat/base.ts b/src/configs/flat/base.ts
index 22cb90f..50af21c 100644
--- a/src/configs/flat/base.ts
+++ b/src/configs/flat/base.ts
@@ -14,7 +14,7 @@ export default [
     plugins: {
       get astro(): ESLint.Plugin {
         // eslint-disable-next-line @typescript-eslint/no-require-imports -- ignore
-        return require("../../index")
+        return require("../../plugin-without-config")
       },
     },
   },
diff --git a/src/configs/recommended.ts b/src/configs/recommended.ts
index f029a8b..3556092 100644
--- a/src/configs/recommended.ts
+++ b/src/configs/recommended.ts
@@ -1,11 +1,8 @@
 // IMPORTANT!
 // This file has been automatically generated,
 // in order to update its content execute "npm run update"
-import path from "path"
-const base = require.resolve("./base")
-const baseExtend =
-  path.extname(`${base}`) === ".ts" ? "plugin:astro/base" : base
-export = {
+const baseExtend = "plugin:astro/base"
+export default {
   extends: [baseExtend],
   rules: {
     // eslint-plugin-astro rules
diff --git a/src/index.cts b/src/index.cts
new file mode 100644
index 0000000..1db9245
--- /dev/null
+++ b/src/index.cts
@@ -0,0 +1,4 @@
+import { buildCjsConfigs } from "./plugin-config-builder"
+import { meta, rules, processors, environments } from "./plugin-without-config"
+const configs = buildCjsConfigs()
+export = { meta, configs, rules, processors, environments }
diff --git a/src/index.mts b/src/index.mts
new file mode 100644
index 0000000..8e2cd25
--- /dev/null
+++ b/src/index.mts
@@ -0,0 +1,5 @@
+import { buildEsmConfigs } from "./plugin-config-builder"
+import { meta, rules, processors, environments } from "./plugin-without-config"
+const configs = buildEsmConfigs()
+export default { meta, configs, rules, processors, environments }
+export { meta, configs, rules, processors, environments }
diff --git a/src/index.ts b/src/index.ts
deleted file mode 100644
index 4e1e6d9..0000000
--- a/src/index.ts
+++ /dev/null
@@ -1,52 +0,0 @@
-import type { RuleModule } from "./types"
-import { rules as ruleList } from "./utils/rules"
-import * as processors from "./processor"
-import { environments } from "./environments"
-import base from "./configs/base"
-import recommended from "./configs/recommended"
-import all from "./configs/all"
-import flatBase from "./configs/flat/base"
-import flatRecommended from "./configs/flat/recommended"
-import flatAll from "./configs/flat/all"
-import { buildA11yConfigs } from "./a11y"
-import * as meta from "./meta"
-import type { Linter } from "eslint"
-
-const configs = {
-  base: base as unknown as Linter.Config,
-  recommended: recommended as Linter.Config,
-  all: all as Linter.Config,
-  "flat/base": flatBase as Linter.FlatConfig[],
-  "flat/recommended": flatRecommended as Linter.FlatConfig[],
-  "flat/all": flatAll as Linter.FlatConfig[],
-}
-
-const a11yConfigs = buildA11yConfigs()
-for (const configName of Object.keys(a11yConfigs)) {
-  Object.defineProperty(configs, configName, {
-    enumerable: true,
-    get() {
-      return a11yConfigs[configName]
-    },
-  })
-}
-
-const rules = ruleList.reduce(
-  (obj, r) => {
-    obj[r.meta.docs.ruleName] = r
-    return obj
-  },
-  {} as { [key: string]: RuleModule },
-)
-
-export = {
-  meta,
-  configs,
-  rules,
-  processors: {
-    ".astro": processors.astroProcessor,
-    astro: processors.astroProcessor,
-    "client-side-ts": processors.clientSideTsProcessor,
-  },
-  environments,
-}
diff --git a/src/plugin-config-builder.ts b/src/plugin-config-builder.ts
new file mode 100644
index 0000000..3006db8
--- /dev/null
+++ b/src/plugin-config-builder.ts
@@ -0,0 +1,109 @@
+import base from "./configs/base"
+import recommended from "./configs/recommended"
+import all from "./configs/all"
+import flatBase from "./configs/flat/base"
+import flatRecommended from "./configs/flat/recommended"
+import flatAll from "./configs/flat/all"
+import { buildA11yFlatConfigs, buildA11yLegacyConfigs } from "./a11y"
+import type { Linter } from "eslint"
+
+type ESMConfigs = {
+  base: Linter.FlatConfig[]
+  recommended: Linter.FlatConfig[]
+  all: Linter.FlatConfig[]
+  "jsx-a11y-strict": Linter.FlatConfig[]
+  "jsx-a11y-recommended": Linter.FlatConfig[]
+  // For backward compatibility
+  "flat/base": Linter.FlatConfig[]
+  "flat/recommended": Linter.FlatConfig[]
+  "flat/all": Linter.FlatConfig[]
+  "flat/jsx-a11y-strict": Linter.FlatConfig[]
+  "flat/jsx-a11y-recommended": Linter.FlatConfig[]
+}
+/**
+ * Build configs for ESM Module
+ */
+export function buildEsmConfigs(): ESMConfigs {
+  const esmConfigs: ESMConfigs = {
+    base: flatBase as Linter.FlatConfig[],
+    recommended: flatRecommended as Linter.FlatConfig[],
+    all: flatAll as Linter.FlatConfig[],
+    "jsx-a11y-strict": null as never,
+    "jsx-a11y-recommended": null as never,
+    // For backward compatibility
+    "flat/base": flatBase as Linter.FlatConfig[],
+    "flat/recommended": flatRecommended as Linter.FlatConfig[],
+    "flat/all": flatAll as Linter.FlatConfig[],
+    "flat/jsx-a11y-strict": null as never,
+    "flat/jsx-a11y-recommended": null as never,
+  }
+
+  const a11yFlatConfigs = buildA11yFlatConfigs()
+  for (const configName of Object.keys(a11yFlatConfigs)) {
+    Object.defineProperty(esmConfigs, configName, {
+      enumerable: true,
+      get() {
+        return a11yFlatConfigs[configName]
+      },
+    })
+    Object.defineProperty(esmConfigs, `flat/${configName}`, {
+      enumerable: true,
+      get() {
+        return a11yFlatConfigs[configName]
+      },
+    })
+  }
+
+  return esmConfigs
+}
+
+type CJSConfigs = {
+  base: Linter.Config
+  recommended: Linter.Config
+  all: Linter.Config
+  "jsx-a11y-strict": Linter.Config
+  "jsx-a11y-recommended": Linter.Config
+  "flat/base": Linter.FlatConfig[]
+  "flat/recommended": Linter.FlatConfig[]
+  "flat/all": Linter.FlatConfig[]
+  "flat/jsx-a11y-strict": Linter.FlatConfig[]
+  "flat/jsx-a11y-recommended": Linter.FlatConfig[]
+}
+
+/**
+ * Build configs for CJS Module
+ */
+export function buildCjsConfigs(): CJSConfigs {
+  const cjsConfigs: CJSConfigs = {
+    base: base as never,
+    recommended: recommended as Linter.Config,
+    all: all as Linter.Config,
+    "jsx-a11y-strict": null as never as Linter.Config,
+    "jsx-a11y-recommended": null as never as Linter.Config,
+    "flat/base": flatBase as Linter.FlatConfig[],
+    "flat/recommended": flatRecommended as Linter.FlatConfig[],
+    "flat/all": flatAll as Linter.FlatConfig[],
+    "flat/jsx-a11y-strict": null as never as Linter.FlatConfig[],
+    "flat/jsx-a11y-recommended": null as never as Linter.FlatConfig[],
+  }
+
+  const a11yFlatConfigs = buildA11yFlatConfigs()
+  for (const configName of Object.keys(a11yFlatConfigs)) {
+    Object.defineProperty(cjsConfigs, `flat/${configName}`, {
+      enumerable: true,
+      get() {
+        return a11yFlatConfigs[configName]
+      },
+    })
+  }
+  const a11yLegacyConfigs = buildA11yLegacyConfigs()
+  for (const configName of Object.keys(a11yLegacyConfigs)) {
+    Object.defineProperty(cjsConfigs, configName, {
+      enumerable: true,
+      get() {
+        return a11yLegacyConfigs[configName]
+      },
+    })
+  }
+  return cjsConfigs
+}
diff --git a/src/plugin-without-config.ts b/src/plugin-without-config.ts
new file mode 100644
index 0000000..26fd0ca
--- /dev/null
+++ b/src/plugin-without-config.ts
@@ -0,0 +1,20 @@
+import { rules as ruleList } from "./utils/rules"
+import * as processorsDefines from "./processor"
+import type { Rule } from "eslint"
+
+export * as meta from "./meta"
+export { environments } from "./environments"
+
+export const rules = ruleList.reduce(
+  (obj, r) => {
+    obj[r.meta.docs.ruleName] = r as never
+    return obj
+  },
+  {} as { [key: string]: Rule.RuleModule },
+)
+
+export const processors = {
+  ".astro": processorsDefines.astroProcessor,
+  astro: processorsDefines.astroProcessor,
+  "client-side-ts": processorsDefines.clientSideTsProcessor,
+}
diff --git a/src/shared/client-script/index.ts b/src/shared/client-script/index.ts
index 81ce3f9..929caa2 100644
--- a/src/shared/client-script/index.ts
+++ b/src/shared/client-script/index.ts
@@ -1,4 +1,3 @@
-// @ts-expect-error -- bug?
 import type { ElementNode, TextNode } from "@astrojs/compiler/types"
 import type { ParseTemplateResult } from "astro-eslint-parser"
 import type { Linter } from "eslint"
diff --git a/src/shared/index.ts b/src/shared/index.ts
index ea6babd..841a59e 100644
--- a/src/shared/index.ts
+++ b/src/shared/index.ts
@@ -1,5 +1,4 @@
 import { ClientScript } from "./client-script"
-// @ts-expect-error -- bug?
 import type { ElementNode } from "@astrojs/compiler/types"
 import type { ParseTemplateResult } from "astro-eslint-parser"
 
diff --git a/tools/update-rulesets.ts b/tools/update-rulesets.ts
index 7147cf4..8e80fc5 100644
--- a/tools/update-rulesets.ts
+++ b/tools/update-rulesets.ts
@@ -14,7 +14,7 @@ void formatAndSave(
  */
 import { hasTypescriptEslintParser } from "./has-typescript-eslint-parser"
 
-export = {
+export default {
   plugins: ["astro"],
   overrides: [
     {
@@ -110,7 +110,7 @@ export default [
     plugins: {
       get astro(): ESLint.Plugin {
         // eslint-disable-next-line @typescript-eslint/no-require-imports -- ignore
-        return require("../../index")
+        return require("../../plugin-without-config")
       },
     },
   },
@@ -191,11 +191,8 @@ void formatAndSave(
  * This file has been automatically generated,
  * in order to update its content execute "npm run update"
  */
-import path from "path"
-const base = require.resolve("./base")
-const baseExtend =
-  path.extname(\`\${base}\`) === ".ts" ? "plugin:astro/base" : base
-export = {
+const baseExtend = "plugin:astro/base"
+export default {
   extends: [baseExtend],
   rules: {
     // eslint-plugin-astro rules
diff --git a/tsconfig.build.json b/tsconfig.build.json
deleted file mode 100644
index 31f3e26..0000000
--- a/tsconfig.build.json
+++ /dev/null
@@ -1,13 +0,0 @@
-{
-  "extends": "./tsconfig.json",
-  "exclude": [
-    "tests/**/*",
-    "tools/**/*",
-    "typings/**/*",
-    "docs-build/src/**/*",
-    "docs/**/*"
-  ],
-  "compilerOptions": {
-    "removeComments": true /* Do not emit comments to output. */
-  }
-}
diff --git a/tsconfig.json b/tsconfig.json
index 15b1d12..69c7a38 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,8 +1,8 @@
 {
   "compilerOptions": {
     "target": "es2015",
-    "module": "Node16",
-    "moduleResolution": "Node16",
+    "module": "preserve",
+    "moduleResolution": "Bundler",
     "lib": ["es2020", "dom"],
     "allowJs": true,
     "checkJs": true,
@@ -25,7 +25,10 @@
     },
 
     "skipLibCheck": true,
-    "resolveJsonModule": true
+    "resolveJsonModule": true,
+    "allowSyntheticDefaultImports": true,
+    "allowImportingTsExtensions": true,
+    "noEmit": true
   },
   "include": [
     "src/**/*",
@@ -37,7 +40,8 @@
     "docs-build/src/**/*.astro",
     "docs-build/src/**/*.svelte",
     "docs/**/*.astro",
-    "typings/**/*"
+    "typings/**/*",
+    "tsup.config.ts"
   ],
   "exclude": ["lib/**/*", "tests/fixtures/**/*"]
 }
diff --git a/tsup.config.ts b/tsup.config.ts
new file mode 100644
index 0000000..6533d78
--- /dev/null
+++ b/tsup.config.ts
@@ -0,0 +1,23 @@
+import type { Options } from "tsup"
+import { defineConfig } from "tsup"
+
+const base: Options = {
+  clean: true,
+  dts: true,
+  outDir: "lib",
+  treeshake: true,
+  external: ["@typescript-eslint/parser", "eslint-plugin-jsx-a11y", "espree"],
+}
+
+export default defineConfig([
+  {
+    ...base,
+    entry: ["src/index.mts"],
+    format: ["esm"],
+  },
+  {
+    ...base,
+    entry: ["src/index.cts"],
+    format: ["cjs"],
+  },
+])


Test patch:
diff --git a/tests/src/config/recommended.ts b/tests/src/config/recommended.ts
index 913dcf6..29b8a06 100644
--- a/tests/src/config/recommended.ts
+++ b/tests/src/config/recommended.ts
@@ -1,5 +1,5 @@
 import assert from "assert"
-import plugin from "../../../src/index"
+import plugin from "../../../src/index.cts"
 import { LegacyESLint, FlatESLint } from "../../utils/eslint-compat"
 
 const code = `---
@@ -16,7 +16,7 @@ describe("`recommended` config", () => {
   it("legacy `recommended` config should work. ", async () => {
     const linter = new LegacyESLint({
       plugins: {
-        toml: plugin as never,
+        astro: plugin as never,
       },
       baseConfig: {
         parserOptions: {
diff --git a/tests/src/integration/client-javascript.ts b/tests/src/integration/client-javascript.ts
index 41a8b77..164b3a8 100644
--- a/tests/src/integration/client-javascript.ts
+++ b/tests/src/integration/client-javascript.ts
@@ -1,5 +1,5 @@
 import { ESLint } from "eslint"
-import astroPlugin from "../../../src/index"
+import astroPlugin from "../../../src/index.cts"
 import assert from "assert"
 import Module from "module"
 import semver from "semver"
diff --git a/tests/src/integration/client-typescript.ts b/tests/src/integration/client-typescript.ts
index 603e961..0921f1f 100644
--- a/tests/src/integration/client-typescript.ts
+++ b/tests/src/integration/client-typescript.ts
@@ -1,5 +1,5 @@
 import { ESLint } from "eslint"
-import astroPlugin from "../../../src/index"
+import astroPlugin from "../../../src/index.cts"
 import assert from "assert"
 import Module from "module"
 import semver from "semver"
diff --git a/tests/src/integration/config-for-a11y.ts b/tests/src/integration/config-for-a11y.ts
index 33160a9..71ef98a 100644
--- a/tests/src/integration/config-for-a11y.ts
+++ b/tests/src/integration/config-for-a11y.ts
@@ -1,7 +1,7 @@
 import { ESLint } from "eslint"
 // @ts-expect-error -- ignore
 import jsxA11yPlugin from "eslint-plugin-jsx-a11y"
-import astroPlugin from "../../../src/index"
+import astroPlugin from "../../../src/index.cts"
 import assert from "assert"
 import Module from "module"
 import semver from "semver"
diff --git a/tests/src/integration/parse-error.ts b/tests/src/integration/parse-error.ts
index cf4d598..2f5ffc3 100644
--- a/tests/src/integration/parse-error.ts
+++ b/tests/src/integration/parse-error.ts
@@ -1,5 +1,5 @@
 import { ESLint } from "eslint"
-import astroPlugin from "../../../src/index"
+import astroPlugin from "../../../src/index.cts"
 import assert from "assert"
 import Module from "module"
 import semver from "semver"
diff --git a/tests/src/meta.ts b/tests/src/meta.ts
index f1110e3..fbd0383 100644
--- a/tests/src/meta.ts
+++ b/tests/src/meta.ts
@@ -1,5 +1,5 @@
 import assert from "assert"
-import plugin from "../../src"
+import * as plugin from "../../src/plugin-without-config"
 import { version } from "../../package.json"
 const expectedMeta = {
   name: "eslint-plugin-astro",
diff --git a/tests/typing.test.ts b/tests/typing.test.ts
index 20fe3bd..efab098 100644
--- a/tests/typing.test.ts
+++ b/tests/typing.test.ts
@@ -1,7 +1,7 @@
 import type { Linter } from "eslint"
 import { expectTypeOf } from "expect-type"
 import tseslint from "typescript-eslint"
-import plugin from "../src/index"
+import * as plugin from "../src/index.mts"
 
 expectTypeOf([...plugin.configs["flat/base"]]).toMatchTypeOf<
   Linter.FlatConfig[]
diff --git a/tests/utils/utils.ts b/tests/utils/utils.ts
index 201f400..db63041 100644
--- a/tests/utils/utils.ts
+++ b/tests/utils/utils.ts
@@ -3,8 +3,7 @@ import path from "path"
 import type { RuleTester } from "eslint"
 import { getLinter as getCompatLinter } from "eslint-compat-utils/linter"
 import * as astroESLintParser from "astro-eslint-parser"
-// eslint-disable-next-line @typescript-eslint/no-require-imports -- tests
-import plugin = require("../../src/index")
+import * as plugin from "../../src/plugin-without-config"
 import { applyFixes } from "./source-code-fixer"
 // eslint-disable-next-line @typescript-eslint/naming-convention -- class name
 const Linter = getCompatLinter()
@@ -85,7 +84,7 @@ export function loadTestCases(
     .filter(filter)
     .map((inputFile) => getConfig(ruleName, inputFile))
 
-  const fixable = plugin.rules[ruleName].meta.fixable != null
+  const fixable = plugin.rules[ruleName].meta!.fixable != null
 
   const invalid = listupInput(invalidFixtureRoot)
     .filter((file) => !path.basename(file).startsWith("_"))
@@ -213,7 +212,7 @@ function writeFixtures(
   if (force || !fs.existsSync(outputFile)) {
     const output = applyFixes(config.code, result).output
 
-    if (plugin.rules[ruleName].meta.fixable != null) {
+    if (plugin.rules[ruleName].meta!.fixable != null) {
       fs.writeFileSync(outputFile, output, "utf8")
     }
   }