{"id":8799,"date":"2025-10-09T17:20:18","date_gmt":"2025-10-09T17:20:18","guid":{"rendered":"https:\/\/pokecon.jp\/job\/?p=8799"},"modified":"2025-10-09T17:20:18","modified_gmt":"2025-10-09T17:20:18","slug":"oxlint-js-plugins-preview-the-javascript-oxidation-compiler","status":"publish","type":"post","link":"https:\/\/pokecon.jp\/job\/8799\/","title":{"rendered":"Oxlint JS Plugins Preview | The JavaScript Oxidation Compiler"},"content":{"rendered":"\n<\/p>\n<div>\n<header class=\"AppBlogPostHeader\" data-v-007a27e9=\"\"\/>\n<p>Earlier this year <a target=\"_blank\" href=\"https:\/\/github.com\/oxc-project\/oxc\/discussions\/10342\" target=\"_blank\" rel=\"noreferrer\">we asked for input from the community<\/a> to inform design for Oxlint support for custom JS plugins. Today, we are pleased to announce the result of many months of research, prototyping, and finally building:<\/p>\n<p><strong>Oxlint supports plugins written in JS!<\/strong><\/p>\n<h4 id=\"key-features\" tabindex=\"-1\">Key features <a target=\"_blank\" class=\"header-anchor\" href=\"#key-features\" aria-label=\"Permalink to \u201cKey features\u201d\">\u200b<\/a><\/h4>\n<ul>\n<li>ESLint-compatible plugin API. Oxlint will be able to run many existing ESLint plugins without modification.<\/li>\n<li>An alternative API which is slightly different, and unlocks better performance.<\/li>\n<\/ul>\n<h4 id=\"what-this-is-and-isn-t\" tabindex=\"-1\">What this is and isn&#8217;t <a target=\"_blank\" class=\"header-anchor\" href=\"#what-this-is-and-isn-t\" aria-label=\"Permalink to \u201cWhat this is and isn't\u201d\">\u200b<\/a><\/h4>\n<p>This preview release is just the beginning. It is important to note that:<\/p>\n<ul>\n<li>This initial release does not implement all of ESLint&#8217;s plugin API.<\/li>\n<li>Performance is good, but it&#8217;s going to get <em>way<\/em> better &#8211; we have many optimizations in the pipeline.<\/li>\n<\/ul>\n<p>The most commonly-used APIs for code-checking rules <a target=\"_blank\" href=\"#features\">are implemented<\/a>, so many existing ESLint rules will already work. But token-related APIs are absent, so stylistic (formatting) rules will not.<\/p>\n<p>We invite users to take it for a spin, give feedback, and inform our priorities for the next phase of development.<\/p>\n<h4 id=\"this-blog-post-covers\" tabindex=\"-1\">This blog post covers <a target=\"_blank\" class=\"header-anchor\" href=\"#this-blog-post-covers\" aria-label=\"Permalink to \u201cThis blog post covers\u201d\">\u200b<\/a><\/h4>\n<ol>\n<li>How to use it.<\/li>\n<li>What&#8217;s coming next.<\/li>\n<li>Some of the technical details that enable our &#8220;have cake and eat it&#8221; approach of providing both ESLint compatibility <strong>and<\/strong> excellent performance.<\/li>\n<\/ol>\n<h2 id=\"quick-start\" tabindex=\"-1\">Quick Start <a target=\"_blank\" class=\"header-anchor\" href=\"#quick-start\" aria-label=\"Permalink to \u201cQuick Start\u201d\">\u200b<\/a><\/h2>\n<p>Install Oxlint in your project:<\/p>\n<p>Write a custom JS plugin:<\/p>\n<div class=\"language-js\"><button title=\"Copy Code\" class=\"copy\"\/><span class=\"lang\">js<\/span><\/p>\n<pre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;\" tabindex=\"0\" dir=\"ltr\"><code><span class=\"line\"><span style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D;\">\/\/ plugin.js<\/span><\/span>\n<span class=\"line\"\/>\n<span class=\"line\"><span style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D;\">\/\/ The simplest rule of all - no debugger<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">const<\/span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\"> rule<\/span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\"> =<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0;\">  create<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">(<\/span><span style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70;\">context<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">    return<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0;\">      DebuggerStatement<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">(<\/span><span style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70;\">node<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">        context.<\/span><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0;\">report<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">({<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">          message: <\/span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF;\">\"No debugger!\"<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">,<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">          node,<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">        });<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">      },<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">    };<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">  },<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">};<\/span><\/span>\n<span class=\"line\"\/>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">const<\/span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\"> plugin<\/span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\"> =<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">  meta: {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">    name: <\/span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF;\">\"best-plugin-ever\"<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">,<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">  },<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">  rules: {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF;\">    \"no-debugger\"<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">: rule,<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">  },<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">};<\/span><\/span>\n<span class=\"line\"\/>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">export<\/span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\"> default<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\"> plugin;<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>Create config file enabling the plugin:<\/p>\n<div class=\"language-json\"><button title=\"Copy Code\" class=\"copy\"\/><span class=\"lang\">json<\/span><\/p>\n<pre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;\" tabindex=\"0\" dir=\"ltr\"><code><span class=\"line\"><span style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D;\">\/\/ .oxlintrc.json<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">{<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\">  \"jsPlugins\"<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">: [<\/span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF;\">\".\/plugin.js\"<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">],<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\">  \"rules\"<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">: {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\">    \"best-plugin-ever\/no-debugger\"<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">: <\/span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF;\">\"error\"<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">  }<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">}<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>Add a file to be linted:<\/p>\n<p>Run Oxlint:<\/p>\n<p>Expect to see:<\/p>\n<div class=\"language-\"><button title=\"Copy Code\" class=\"copy\"\/><span class=\"lang\"\/><\/p>\n<pre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;\" tabindex=\"0\" dir=\"ltr\"><code><span class=\"line\"><span> x best-plugin-ever(no-debugger): No debugger!<\/span><\/span>\n<span class=\"line\"><span>  ,-[foo.js:1:1]<\/span><\/span>\n<span class=\"line\"><span>1 | debugger;<\/span><\/span>\n<span class=\"line\"><span>  : ^^^^^^^^^<\/span><\/span>\n<span class=\"line\"><span>  `----<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>For further details on authoring plugins, see <a target=\"_blank\" href=\"https:\/\/oxc.rs\/docs\/guide\/usage\/linter\/js-plugins\">the docs<\/a>.<\/p>\n<h2 id=\"alternative-api\" tabindex=\"-1\">Alternative API <a target=\"_blank\" class=\"header-anchor\" href=\"#alternative-api\" aria-label=\"Permalink to \u201cAlternative API\u201d\">\u200b<\/a><\/h2>\n<p>Oxlint also offers a slightly different API which unlocks better performance.<\/p>\n<p><strong>This alternative API produces plugins which are compatible with ESLint, as well as Oxlint.<\/strong><\/p>\n<p>Example rule that flags files containing more than 5 class declarations:<\/p>\n<h4 id=\"eslint-version\" tabindex=\"-1\">ESLint version <a target=\"_blank\" class=\"header-anchor\" href=\"#eslint-version\" aria-label=\"Permalink to \u201cESLint version\u201d\">\u200b<\/a><\/h4>\n<div class=\"language-js\"><button title=\"Copy Code\" class=\"copy\"\/><span class=\"lang\">js<\/span><\/p>\n<pre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;\" tabindex=\"0\" dir=\"ltr\"><code><span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">const<\/span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\"> rule<\/span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\"> =<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0;\">  create<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">(<\/span><span style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70;\">context<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">    let<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\"> classCount <\/span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">=<\/span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\"> 0<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">;<\/span><\/span>\n<span class=\"line\"\/>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">    return<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0;\">      ClassDeclaration<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">(<\/span><span style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70;\">node<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">        classCount<\/span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">++<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">        if<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\"> (classCount <\/span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">===<\/span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\"> 6<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">          context.<\/span><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0;\">report<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">({ message: <\/span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF;\">\"Too many classes\"<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">, node });<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">      },<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">    };<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">  },<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">};<\/span><\/span><\/code><\/pre>\n<\/div>\n<h4 id=\"alternative-api-version\" tabindex=\"-1\">Alternative API version <a target=\"_blank\" class=\"header-anchor\" href=\"#alternative-api-version\" aria-label=\"Permalink to \u201cAlternative API version\u201d\">\u200b<\/a><\/h4>\n<div class=\"language-js\"><button title=\"Copy Code\" class=\"copy\"\/><span class=\"lang\">js<\/span><\/p>\n<pre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;\" tabindex=\"0\" dir=\"ltr\"><code><span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">import<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\"> { defineRule } <\/span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">from<\/span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF;\"> \"oxlint\"<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">;<\/span><\/span>\n<span class=\"line\"\/>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">const<\/span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\"> rule<\/span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\"> =<\/span><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0;\"> defineRule<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">({<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0;\">  createOnce<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">(<\/span><span style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70;\">context<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D;\">    \/\/ Define counter variable<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">    let<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\"> classCount;<\/span><\/span>\n<span class=\"line\"\/>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">    return<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\"> {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0;\">      before<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">() {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D;\">        \/\/ Reset counter before traversing AST of each file<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">        classCount <\/span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">=<\/span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\"> 0<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">      },<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#6A737D;--shiki-dark:#6A737D;\">      \/\/ Same as before<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0;\">      ClassDeclaration<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">(<\/span><span style=\"--shiki-light:#E36209;--shiki-dark:#FFAB70;\">node<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">        classCount<\/span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">++<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">;<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">        if<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\"> (classCount <\/span><span style=\"--shiki-light:#D73A49;--shiki-dark:#F97583;\">===<\/span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\"> 6<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">) {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">          context.<\/span><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0;\">report<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">({ message: <\/span><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF;\">\"Too many classes\"<\/span><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">, node });<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">        }<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">      },<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">    };<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">  },<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">});<\/span><\/span><\/code><\/pre>\n<\/div>\n<h4 id=\"the-differences\" tabindex=\"-1\">The differences <a target=\"_blank\" class=\"header-anchor\" href=\"#the-differences\" aria-label=\"Permalink to \u201cThe differences\u201d\">\u200b<\/a><\/h4>\n<ol>\n<li>Wrap the rule object in <code>defineRule(...)<\/code>.<\/li>\n<\/ol>\n<div class=\"language-diff\"><button title=\"Copy Code\" class=\"copy\"\/><span class=\"lang\">diff<\/span><\/p>\n<pre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;\" tabindex=\"0\" dir=\"ltr\"><code><span class=\"line\"><span style=\"--shiki-light:#B31D28;--shiki-dark:#FDAEB7;\">- const rule = {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#22863A;--shiki-dark:#85E89D;\">+ const rule = defineRule({<\/span><\/span><\/code><\/pre>\n<\/div>\n<ol start=\"2\">\n<li>Use <code>createOnce<\/code> instead of <code>create<\/code>.<\/li>\n<\/ol>\n<div class=\"language-diff\"><button title=\"Copy Code\" class=\"copy\"\/><span class=\"lang\">diff<\/span><\/p>\n<pre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;\" tabindex=\"0\" dir=\"ltr\"><code><span class=\"line\"><span style=\"--shiki-light:#B31D28;--shiki-dark:#FDAEB7;\">-   create(context) {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#22863A;--shiki-dark:#85E89D;\">+   createOnce(context) {<\/span><\/span><\/code><\/pre>\n<\/div>\n<ol start=\"3\">\n<li>Move any per-file setup from body of <code>create<\/code> into <code>before<\/code> hook.<\/li>\n<\/ol>\n<div class=\"language-diff\"><button title=\"Copy Code\" class=\"copy\"\/><span class=\"lang\">diff<\/span><\/p>\n<pre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;\" tabindex=\"0\" dir=\"ltr\"><code><span class=\"line\"><span style=\"--shiki-light:#B31D28;--shiki-dark:#FDAEB7;\">-     let classCount = 0;<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#22863A;--shiki-dark:#85E89D;\">+     let classCount;<\/span><\/span>\n<span class=\"line\"\/>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">      return {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#22863A;--shiki-dark:#85E89D;\">+       before() {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#22863A;--shiki-dark:#85E89D;\">+         classCount = 0; \/\/ Reset counter<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#22863A;--shiki-dark:#85E89D;\">+       },<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">        ClassDeclaration(node) {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">          classCount++;<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">          if (classCount === 6) {<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">            context.report({ message: \"Too many classes\", node });<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">          }<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">        },<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">      };<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">    },<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#24292E;--shiki-dark:#E1E4E8;\">  });<\/span><\/span><\/code><\/pre>\n<\/div>\n<p>This is the only significant difference &#8211; <code>create<\/code> (ESLint&#8217;s method) is called repeatedly <em>for each file<\/em>, whereas <code>createOnce<\/code> is called once only.<\/p>\n<p>All other APIs behave exactly the same as in ESLint.<\/p>\n<p>The reasons why this alternative API has potential to greatly improve performance are explained in <a target=\"_blank\" href=\"\/docs\/guide\/usage\/linter\/js-plugins#why-is-the-alternative-api-faster\">the docs<\/a>.<\/p>\n<h2 id=\"performance\" tabindex=\"-1\">Performance <a target=\"_blank\" class=\"header-anchor\" href=\"#performance\" aria-label=\"Permalink to \u201cPerformance\u201d\">\u200b<\/a><\/h2>\n<p>As mentioned above, performance is not yet as good as it can be. Our prototyping work has demonstrated significant speed-gains from various optimizations, which we&#8217;ll apply in future releases.<\/p>\n<p>However, even without all those optimizations, the cost of adding JS plugins into the mix is already surprisingly low.<\/p>\n<p>Oxlint vs ESLint linting a medium-sized TypeScript project <a target=\"_blank\" href=\"https:\/\/github.com\/vuejs\/core\" target=\"_blank\" rel=\"noreferrer\">vuejs\/core<\/a>:<\/p>\n<div class=\"s_table\"><table tabindex=\"0\">\n<thead>\n<tr>\n<th>Linter<\/th>\n<th>Time<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>ESLint<\/td>\n<td>7,030 ms<\/td>\n<\/tr>\n<tr>\n<td>ESLint multi-threaded<\/td>\n<td>4,541 ms<\/td>\n<\/tr>\n<tr>\n<td>Oxlint<\/td>\n<td>582 ms<\/td>\n<\/tr>\n<tr>\n<td>Oxlint with custom JS plugin<\/td>\n<td>584 ms<\/td>\n<\/tr>\n<\/tbody>\n<\/table><\/div>\n<div>\n<details>\n<summary>Details<\/summary>\n<div class=\"language-sh\"><button title=\"Copy Code\" class=\"copy\"\/><span class=\"lang\">sh<\/span><\/p>\n<pre class=\"shiki shiki-themes github-light github-dark\" style=\"--shiki-light:#24292e;--shiki-dark:#e1e4e8;--shiki-light-bg:#fff;--shiki-dark-bg:#24292e;\" tabindex=\"0\" dir=\"ltr\"><code><span class=\"line\"><span style=\"--shiki-light:#6F42C1;--shiki-dark:#B392F0;\">hyperfine<\/span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\"> \\<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\">  --warmup<\/span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\"> 1<\/span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\"> \\<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\">  --runs<\/span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\"> 5<\/span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\"> \\<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF;\">  'pnpm run oxlint'<\/span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\"> \\<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF;\">  'pnpm run oxlint-with-custom-plugin'<\/span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\"> \\<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF;\">  'pnpm run eslint-with-custom-plugin'<\/span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\"> \\<\/span><\/span>\n<span class=\"line\"><span style=\"--shiki-light:#032F62;--shiki-dark:#9ECBFF;\">  'pnpm run eslint-with-custom-plugin-parallel'<\/span><span style=\"--shiki-light:#005CC5;--shiki-dark:#79B8FF;\"> -i<\/span><\/span><\/code><\/pre>\n<\/div>\n<\/details>\n<\/div>\n<p>In this example, the cost of adding a simple JS plugin to Oxlint is less than 1%, and Oxlint is 8x faster than ESLint, even using ESLint&#8217;s new multi-threaded runner.<\/p>\n<p>Obviously, more complicated JS plugins, or many of them, will have a higher performance cost &#8211; which is why we will be focused in future releases on driving down that cost further.<\/p>\n<h2 id=\"features\" tabindex=\"-1\">Features <a target=\"_blank\" class=\"header-anchor\" href=\"#features\" aria-label=\"Permalink to \u201cFeatures\u201d\">\u200b<\/a><\/h2>\n<p>Oxlint supports most of ESLint&#8217;s APIs which are typically used in plugins\/rules which rely only on AST inspection. That includes most &#8220;fix code&#8221;-type rules.<\/p>\n<p>It does not yet support token-based APIs, so stylistic (formatting) rules will not work yet.<\/p>\n<h4 id=\"supported\" tabindex=\"-1\">Supported <a target=\"_blank\" class=\"header-anchor\" href=\"#supported\" aria-label=\"Permalink to \u201cSupported\u201d\">\u200b<\/a><\/h4>\n<ul>\n<li>AST traversal<\/li>\n<li>AST exploration (<code>node.parent<\/code>, <code>context.sourceCode.getAncestors<\/code>)<\/li>\n<li>Fixes<\/li>\n<li>Selectors (<a target=\"_blank\" href=\"https:\/\/eslint.org\/docs\/latest\/extend\/selectors\" target=\"_blank\" rel=\"noreferrer\">ESLint docs<\/a>)<\/li>\n<li><code>SourceCode<\/code> APIs (e.g. <code>context.sourceCode.getText(node)<\/code>)<\/li>\n<\/ul>\n<h4 id=\"not-supported-yet\" tabindex=\"-1\">Not supported yet <a target=\"_blank\" class=\"header-anchor\" href=\"#not-supported-yet\" aria-label=\"Permalink to \u201cNot supported yet\u201d\">\u200b<\/a><\/h4>\n<ul>\n<li>Language server (IDE) support<\/li>\n<li>Rule options<\/li>\n<li>Suggestions<\/li>\n<li>Scope analysis<\/li>\n<li><code>SourceCode<\/code> APIs related to tokens and comments (e.g. <code>context.sourceCode.getTokens(node)<\/code>)<\/li>\n<li>Control flow analysis<\/li>\n<\/ul>\n<h2 id=\"what-s-next\" tabindex=\"-1\">What&#8217;s next <a target=\"_blank\" class=\"header-anchor\" href=\"#what-s-next\" aria-label=\"Permalink to \u201cWhat's next\u201d\">\u200b<\/a><\/h2>\n<p>Over the next few months, we will be:<\/p>\n<h4 id=\"_1-filling-out-the-plugin-api-surface\" tabindex=\"-1\">1. Filling out the plugin API surface <a target=\"_blank\" class=\"header-anchor\" href=\"#_1-filling-out-the-plugin-api-surface\" aria-label=\"Permalink to \u201c1. Filling out the plugin API surface\u201d\">\u200b<\/a><\/h4>\n<p>Aim is to support 100% of ESLint&#8217;s plugin API surface, so that Oxlint will eventually be able to run <em>any<\/em> ESLint plugin without modification.<\/p>\n<h4 id=\"_2-improving-performance\" tabindex=\"-1\">2. Improving performance <a target=\"_blank\" class=\"header-anchor\" href=\"#_2-improving-performance\" aria-label=\"Permalink to \u201c2. Improving performance\u201d\">\u200b<\/a><\/h4>\n<p>Performance is already good, but we have proven during our prototyping many significant performance gains from further optimizations. We will apply them, and make JS plugins in Oxlint run at as close to Rust speed as we can get.<\/p>\n<h2 id=\"under-the-hood\" tabindex=\"-1\">Under the hood <a target=\"_blank\" class=\"header-anchor\" href=\"#under-the-hood\" aria-label=\"Permalink to \u201cUnder the hood\u201d\">\u200b<\/a><\/h2>\n<p>The rest of this post is not necessary to use JS plugins with Oxlint. But if you&#8217;re interested in the geeky details of how our implementation works, read on&#8230;<\/p>\n<h3 id=\"the-big-question-to-eslint-compat-or-not-to-eslint-compat\" tabindex=\"-1\">The big question: To ESLint compat or not to ESLint compat? <a target=\"_blank\" class=\"header-anchor\" href=\"#the-big-question-to-eslint-compat-or-not-to-eslint-compat\" aria-label=\"Permalink to \u201cThe big question: To ESLint compat or not to ESLint compat?\u201d\">\u200b<\/a><\/h3>\n<p>The question which <a target=\"_blank\" href=\"https:\/\/github.com\/oxc-project\/oxc\/discussions\/10342\" target=\"_blank\" rel=\"noreferrer\">we posed to the community<\/a> earlier this year was whether Oxlint should aim for an ESLint-compatible plugin API or not.<\/p>\n<p>Obviously, an ESLint-compatible interface is ideal in terms of familiarity and ease of migration from ESLint.<\/p>\n<p>However, Oxlint is known for its excellent performance, and compromising that too much would not be desirable.<\/p>\n<p>The main aim of our prototyping work over past few months has been to quantify what is the trade-off between performance and ESLint compatibility, and to investigate if there&#8217;s a &#8220;have cake and eat it&#8221; solution which satisfies both &#8211; providing an ESLint-compatible API <em>and<\/em> acceptable performance (&#8220;acceptable&#8221; here means pretty damn fast!)<\/p>\n<p>We believe that through a combination of different approaches, we&#8217;ve found a way to satisfy both demands.<\/p>\n<h3 id=\"alternative-api-1\" tabindex=\"-1\">Alternative API <a target=\"_blank\" class=\"header-anchor\" href=\"#alternative-api-1\" aria-label=\"Permalink to \u201cAlternative API\u201d\">\u200b<\/a><\/h3>\n<p>See explanation <a target=\"_blank\" href=\"\/docs\/guide\/usage\/linter\/js-plugins#why-is-the-alternative-api-faster\">in docs<\/a> of why this API unlocks potential for higher performance.<\/p>\n<h3 id=\"raw-transfer\" tabindex=\"-1\">Raw transfer <a target=\"_blank\" class=\"header-anchor\" href=\"#raw-transfer\" aria-label=\"Permalink to \u201cRaw transfer\u201d\">\u200b<\/a><\/h3>\n<p>Tools like Oxc represent the code of a JS\/TS file as an &#8220;AST&#8221; (<a target=\"_blank\" href=\"https:\/\/en.wikipedia.org\/wiki\/Abstract_syntax_tree\" target=\"_blank\" rel=\"noreferrer\">abstract syntax tree<\/a>). ASTs are really big &#8211; much much larger than the source code they represent.<\/p>\n<p>Typically, the biggest barrier to performant interop between JS and native languages like Rust is the serialization and deserialization involved in transferring such large data structures between the &#8220;two worlds&#8221;.<\/p>\n<p>The simplest and most common way to move an AST between JS and Rust is: Serialize the AST to JSON, send it across to JS as a string and then &#8220;rehydrate&#8221; it again with <code>JSON.parse<\/code>. But this is extremely slow. Often the cost of these conversions is so high that they massively outweigh the performance gain of using native code in the first place. Other serialization formats are more efficient than JSON, but they still have a sizeable overhead.<\/p>\n<p>We have developed a scheme &#8220;raw transfer&#8221; which cuts out serialization altogether, by using Rust&#8217;s native memory layout as the serialization format (more details on how it works <a target=\"_blank\" href=\"https:\/\/github.com\/oxc-project\/oxc\/issues\/2409\" target=\"_blank\" rel=\"noreferrer\">here<\/a>).<\/p>\n<p>&#8220;Raw transfer&#8221; is the base of the current implementation of JS plugins.<\/p>\n<h3 id=\"lazy-deserialization\" tabindex=\"-1\">Lazy deserialization <a target=\"_blank\" class=\"header-anchor\" href=\"#lazy-deserialization\" aria-label=\"Permalink to \u201cLazy deserialization\u201d\">\u200b<\/a><\/h3>\n<p>The 2nd biggest enemy of good perf, particularly when running JS across multiple CPU cores in worker threads, is the garbage collector. Every object you create also needs to be destroyed to recover its memory. In JS, this is the job of the garbage collector. JS engines like V8 are highly optimized, but still garbage collection is an expensive process, and GC &#8220;steals&#8221; CPU resources from the actual workload.<\/p>\n<p>We have prototyped an AST visitor which deserializes the AST <em>lazily<\/em>, and only deserializes the parts of the AST which actually <em>need<\/em> to be.<\/p>\n<p>For example, if your lint rule relates to class declarations, this visitor will fly through most of the AST without doing much, and will only create JS objects for <code>ClassDeclaration<\/code> AST nodes, which are then passed to the rule&#8217;s code to process. For the rest of the AST (variable declarations, <code>if<\/code> statements, functions, etc) there is no need to create node objects at all.<\/p>\n<p>This has 2 effects:<\/p>\n<ol>\n<li>Raw transfer cuts the cost of serialization to zero. Laziness dramatically reduces the other side (deserialization) too.<\/li>\n<li>Greatly reduced garbage collector pressure.<\/li>\n<\/ol>\n<p>Deno has taken a similar approach, which is explained brilliantly in <a target=\"_blank\" href=\"https:\/\/marvinh.dev\/blog\/speeding-up-javascript-ecosystem-part-11\/\" target=\"_blank\" rel=\"noreferrer\">Marvin Hagemeister&#8217;s blog post<\/a>, and Deno lint has a superbly efficient implementation.<\/p>\n<p>However, we&#8217;ve found that it&#8217;s the combination of lazy deserialization with &#8220;raw transfer&#8221; which delivers <em>really<\/em> good performance. Our tests have found that, with both these overheads removed, JS plugins can run at much greater speed.<\/p>\n<p>This optimization is not yet included in current version of JS plugins. We will implement it in a future version.<\/p>\n<h2 id=\"try-it-out\" tabindex=\"-1\">Try it out! <a target=\"_blank\" class=\"header-anchor\" href=\"#try-it-out\" aria-label=\"Permalink to \u201cTry it out!\u201d\">\u200b<\/a><\/h2>\n<p>Please try out JS plugins and report your experience. All feedback &#8211; either positive or negative &#8211; is gratefully received.<\/p>\n<p>In particular, if you find that Oxlint is lacking some of the APIs you need for your plugins to work, please let us know. We&#8217;ll be filling in the gaps in the API over the next few months, and will prioritise those for which there&#8217;s greatest demand.<\/p>\n<p>Happy linting!<\/p>\n<\/div>\n\n<br \/><a href=\"https:\/\/oxc.rs\/blog\/2025-10-09-oxlint-js-plugins.html\">\u5143\u306e\u8a18\u4e8b\u3092\u78ba\u8a8d\u3059\u308b <\/a><\/p>\n","protected":false},"excerpt":{"rendered":"Earlier this year we asked for input from the community to inform design for Oxlint support for custom JS plug [&hellip;]","protected":false},"author":1,"featured_media":8800,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[2],"tags":[],"class_list":["post-8799","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-hatena-blog"],"acf":[],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.6 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Oxlint JS Plugins Preview | The JavaScript Oxidation Compiler - \u30dd\u30b1\u30b3\u30f3<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/oxc.rs\/blog\/2025-10-09-oxlint-js-plugins.html\" \/>\n<meta property=\"og:locale\" content=\"ja_JP\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Oxlint JS Plugins Preview | The JavaScript Oxidation Compiler - \u30dd\u30b1\u30b3\u30f3\" \/>\n<meta property=\"og:description\" content=\"Earlier this year we asked for input from the community to inform design for Oxlint support for custom JS plug [&hellip;]\" \/>\n<meta property=\"og:url\" content=\"https:\/\/oxc.rs\/blog\/2025-10-09-oxlint-js-plugins.html\" \/>\n<meta property=\"og:site_name\" content=\"\u30dd\u30b1\u30b3\u30f3\" \/>\n<meta property=\"article:published_time\" content=\"2025-10-09T17:20:18+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/pokecon.jp\/job\/wp-content\/uploads\/2025\/10\/preview-universal.png\" \/>\n\t<meta property=\"og:image:width\" content=\"1280\" \/>\n\t<meta property=\"og:image:height\" content=\"640\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/png\" \/>\n<meta name=\"author\" content=\"info@pokecon.jp\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"\u57f7\u7b46\u8005\" \/>\n\t<meta name=\"twitter:data1\" content=\"info@pokecon.jp\" \/>\n\t<meta name=\"twitter:label2\" content=\"\u63a8\u5b9a\u8aad\u307f\u53d6\u308a\u6642\u9593\" \/>\n\t<meta name=\"twitter:data2\" content=\"8\u5206\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/oxc.rs\\\/blog\\\/2025-10-09-oxlint-js-plugins.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/pokecon.jp\\\/job\\\/8799\\\/\"},\"author\":{\"name\":\"info@pokecon.jp\",\"@id\":\"https:\\\/\\\/pokecon.jp\\\/job\\\/#\\\/schema\\\/person\\\/16c9f07b1ba984d165d9aee259bda997\"},\"headline\":\"Oxlint JS Plugins Preview | The JavaScript Oxidation Compiler\",\"datePublished\":\"2025-10-09T17:20:18+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/pokecon.jp\\\/job\\\/8799\\\/\"},\"wordCount\":1376,\"image\":{\"@id\":\"https:\\\/\\\/oxc.rs\\\/blog\\\/2025-10-09-oxlint-js-plugins.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/pokecon.jp\\\/job\\\/wp-content\\\/uploads\\\/2025\\\/10\\\/preview-universal.png\",\"articleSection\":[\"\u306f\u3066\u306a\u30d6\u30ed\u30b0\"],\"inLanguage\":\"ja\"},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/pokecon.jp\\\/job\\\/8799\\\/\",\"url\":\"https:\\\/\\\/oxc.rs\\\/blog\\\/2025-10-09-oxlint-js-plugins.html\",\"name\":\"Oxlint JS Plugins Preview | The JavaScript Oxidation Compiler - \u30dd\u30b1\u30b3\u30f3\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/pokecon.jp\\\/job\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/oxc.rs\\\/blog\\\/2025-10-09-oxlint-js-plugins.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/oxc.rs\\\/blog\\\/2025-10-09-oxlint-js-plugins.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/pokecon.jp\\\/job\\\/wp-content\\\/uploads\\\/2025\\\/10\\\/preview-universal.png\",\"datePublished\":\"2025-10-09T17:20:18+00:00\",\"author\":{\"@id\":\"https:\\\/\\\/pokecon.jp\\\/job\\\/#\\\/schema\\\/person\\\/16c9f07b1ba984d165d9aee259bda997\"},\"breadcrumb\":{\"@id\":\"https:\\\/\\\/oxc.rs\\\/blog\\\/2025-10-09-oxlint-js-plugins.html#breadcrumb\"},\"inLanguage\":\"ja\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/oxc.rs\\\/blog\\\/2025-10-09-oxlint-js-plugins.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"ja\",\"@id\":\"https:\\\/\\\/oxc.rs\\\/blog\\\/2025-10-09-oxlint-js-plugins.html#primaryimage\",\"url\":\"https:\\\/\\\/pokecon.jp\\\/job\\\/wp-content\\\/uploads\\\/2025\\\/10\\\/preview-universal.png\",\"contentUrl\":\"https:\\\/\\\/pokecon.jp\\\/job\\\/wp-content\\\/uploads\\\/2025\\\/10\\\/preview-universal.png\",\"width\":1280,\"height\":640},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/oxc.rs\\\/blog\\\/2025-10-09-oxlint-js-plugins.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"\u30db\u30fc\u30e0\",\"item\":\"https:\\\/\\\/pokecon.jp\\\/job\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Oxlint JS Plugins Preview | The JavaScript Oxidation Compiler\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/pokecon.jp\\\/job\\\/#website\",\"url\":\"https:\\\/\\\/pokecon.jp\\\/job\\\/\",\"name\":\"\u30dd\u30b1\u30b3\u30f3\",\"description\":\"\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/pokecon.jp\\\/job\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"ja\"},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/pokecon.jp\\\/job\\\/#\\\/schema\\\/person\\\/16c9f07b1ba984d165d9aee259bda997\",\"name\":\"info@pokecon.jp\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"ja\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/2b0549cd9f7907c092ca5fbb283baf72337f235726e4b46fa39ec0b701ac2fe2?s=96&d=wavatar&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/2b0549cd9f7907c092ca5fbb283baf72337f235726e4b46fa39ec0b701ac2fe2?s=96&d=wavatar&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/2b0549cd9f7907c092ca5fbb283baf72337f235726e4b46fa39ec0b701ac2fe2?s=96&d=wavatar&r=g\",\"caption\":\"info@pokecon.jp\"},\"url\":\"https:\\\/\\\/pokecon.jp\\\/job\\\/author\\\/infopokecon-jp\\\/\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Oxlint JS Plugins Preview | The JavaScript Oxidation Compiler - \u30dd\u30b1\u30b3\u30f3","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/oxc.rs\/blog\/2025-10-09-oxlint-js-plugins.html","og_locale":"ja_JP","og_type":"article","og_title":"Oxlint JS Plugins Preview | The JavaScript Oxidation Compiler - \u30dd\u30b1\u30b3\u30f3","og_description":"Earlier this year we asked for input from the community to inform design for Oxlint support for custom JS plug [&hellip;]","og_url":"https:\/\/oxc.rs\/blog\/2025-10-09-oxlint-js-plugins.html","og_site_name":"\u30dd\u30b1\u30b3\u30f3","article_published_time":"2025-10-09T17:20:18+00:00","og_image":[{"width":1280,"height":640,"url":"https:\/\/pokecon.jp\/job\/wp-content\/uploads\/2025\/10\/preview-universal.png","type":"image\/png"}],"author":"info@pokecon.jp","twitter_card":"summary_large_image","twitter_misc":{"\u57f7\u7b46\u8005":"info@pokecon.jp","\u63a8\u5b9a\u8aad\u307f\u53d6\u308a\u6642\u9593":"8\u5206"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/oxc.rs\/blog\/2025-10-09-oxlint-js-plugins.html#article","isPartOf":{"@id":"https:\/\/pokecon.jp\/job\/8799\/"},"author":{"name":"info@pokecon.jp","@id":"https:\/\/pokecon.jp\/job\/#\/schema\/person\/16c9f07b1ba984d165d9aee259bda997"},"headline":"Oxlint JS Plugins Preview | The JavaScript Oxidation Compiler","datePublished":"2025-10-09T17:20:18+00:00","mainEntityOfPage":{"@id":"https:\/\/pokecon.jp\/job\/8799\/"},"wordCount":1376,"image":{"@id":"https:\/\/oxc.rs\/blog\/2025-10-09-oxlint-js-plugins.html#primaryimage"},"thumbnailUrl":"https:\/\/pokecon.jp\/job\/wp-content\/uploads\/2025\/10\/preview-universal.png","articleSection":["\u306f\u3066\u306a\u30d6\u30ed\u30b0"],"inLanguage":"ja"},{"@type":"WebPage","@id":"https:\/\/pokecon.jp\/job\/8799\/","url":"https:\/\/oxc.rs\/blog\/2025-10-09-oxlint-js-plugins.html","name":"Oxlint JS Plugins Preview | The JavaScript Oxidation Compiler - \u30dd\u30b1\u30b3\u30f3","isPartOf":{"@id":"https:\/\/pokecon.jp\/job\/#website"},"primaryImageOfPage":{"@id":"https:\/\/oxc.rs\/blog\/2025-10-09-oxlint-js-plugins.html#primaryimage"},"image":{"@id":"https:\/\/oxc.rs\/blog\/2025-10-09-oxlint-js-plugins.html#primaryimage"},"thumbnailUrl":"https:\/\/pokecon.jp\/job\/wp-content\/uploads\/2025\/10\/preview-universal.png","datePublished":"2025-10-09T17:20:18+00:00","author":{"@id":"https:\/\/pokecon.jp\/job\/#\/schema\/person\/16c9f07b1ba984d165d9aee259bda997"},"breadcrumb":{"@id":"https:\/\/oxc.rs\/blog\/2025-10-09-oxlint-js-plugins.html#breadcrumb"},"inLanguage":"ja","potentialAction":[{"@type":"ReadAction","target":["https:\/\/oxc.rs\/blog\/2025-10-09-oxlint-js-plugins.html"]}]},{"@type":"ImageObject","inLanguage":"ja","@id":"https:\/\/oxc.rs\/blog\/2025-10-09-oxlint-js-plugins.html#primaryimage","url":"https:\/\/pokecon.jp\/job\/wp-content\/uploads\/2025\/10\/preview-universal.png","contentUrl":"https:\/\/pokecon.jp\/job\/wp-content\/uploads\/2025\/10\/preview-universal.png","width":1280,"height":640},{"@type":"BreadcrumbList","@id":"https:\/\/oxc.rs\/blog\/2025-10-09-oxlint-js-plugins.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"\u30db\u30fc\u30e0","item":"https:\/\/pokecon.jp\/job\/"},{"@type":"ListItem","position":2,"name":"Oxlint JS Plugins Preview | The JavaScript Oxidation Compiler"}]},{"@type":"WebSite","@id":"https:\/\/pokecon.jp\/job\/#website","url":"https:\/\/pokecon.jp\/job\/","name":"\u30dd\u30b1\u30b3\u30f3","description":"","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/pokecon.jp\/job\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"ja"},{"@type":"Person","@id":"https:\/\/pokecon.jp\/job\/#\/schema\/person\/16c9f07b1ba984d165d9aee259bda997","name":"info@pokecon.jp","image":{"@type":"ImageObject","inLanguage":"ja","@id":"https:\/\/secure.gravatar.com\/avatar\/2b0549cd9f7907c092ca5fbb283baf72337f235726e4b46fa39ec0b701ac2fe2?s=96&d=wavatar&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/2b0549cd9f7907c092ca5fbb283baf72337f235726e4b46fa39ec0b701ac2fe2?s=96&d=wavatar&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/2b0549cd9f7907c092ca5fbb283baf72337f235726e4b46fa39ec0b701ac2fe2?s=96&d=wavatar&r=g","caption":"info@pokecon.jp"},"url":"https:\/\/pokecon.jp\/job\/author\/infopokecon-jp\/"}]}},"_links":{"self":[{"href":"https:\/\/pokecon.jp\/job\/wp-json\/wp\/v2\/posts\/8799","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/pokecon.jp\/job\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/pokecon.jp\/job\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/pokecon.jp\/job\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/pokecon.jp\/job\/wp-json\/wp\/v2\/comments?post=8799"}],"version-history":[{"count":1,"href":"https:\/\/pokecon.jp\/job\/wp-json\/wp\/v2\/posts\/8799\/revisions"}],"predecessor-version":[{"id":8801,"href":"https:\/\/pokecon.jp\/job\/wp-json\/wp\/v2\/posts\/8799\/revisions\/8801"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/pokecon.jp\/job\/wp-json\/wp\/v2\/media\/8800"}],"wp:attachment":[{"href":"https:\/\/pokecon.jp\/job\/wp-json\/wp\/v2\/media?parent=8799"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/pokecon.jp\/job\/wp-json\/wp\/v2\/categories?post=8799"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/pokecon.jp\/job\/wp-json\/wp\/v2\/tags?post=8799"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}