[
  {
    "path": ".editorconfig",
    "content": "root = true\n\n[*]\nindent_style = tab\nend_of_line = lf\ncharset = utf-8\ntrim_trailing_whitespace = true\ninsert_final_newline = true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug-report.yml",
    "content": "name: 🐛 Bug report\ndescription: Run into a bug? File a report and get the help you need!\nlabels: [bug, pending triage]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        > 💁‍♂️ Keep in mind this is a collaborative effort. Please do your best to debug, communicate, and demonstrate the problem.\n\n        ## 👀 Tell us about the bug\n        A _clear and concise_ description of what the bug is.\n\n  - type: textarea\n    attributes:\n      label: Problem\n      description: Please refrain from describing anything other than the problem.\n      placeholder: |\n        What's the problem?\n        Do you have an error stack trace?\n        Do you have screenshots?\n    validations:\n      required: true\n\n  - type: textarea\n    attributes:\n      label: Expected behavior\n      placeholder: |\n        What did you expect to happen?\n    validations:\n      required: true\n\n  - type: markdown\n    attributes:\n      value: |\n        ## 📋 Minimal reproduction\n        > ⚠️ If a **minimal** reproduction is not provided, **the issue will be closed.**\n\n        The minimal reproduction proves a bug exists in this project, allows others to debug it for you, and streamlines resolution.\n\n        <details>\n          <summary><strong>How do I create a minimal reproduction?</strong></summary>\n\n        1. Delete all unnecessary files and data. Keep it under 10 files.\n\n            Delete irrelevant files (e.g. `LICENSE`, `.npmrc`, `.github`).\n            Do you have unnecessary dependencies, scripts, properties in `package.json`?\n\n        2. Delete all unnecessary code. Reduce the scope.\n\n            Try to narrow the scope of the reproduction as much as possible.\n            Is it a frontend or backend problem? Delete the other.\n            Ideally, the code is reduced to a few lines of code in a single file.\n\n        3. Set the `start` script in `package.json` to the command that demonstrates the bug.\n\n        4. Verify the reproduction.\n\n            Try running it yourself, and check:\n            - Is the problem immediately reproducible?\n            - Are dependencies properly declared?\n            - Could I find more files or code that isn't necessary?\n\n        5. Upload the reproduction to [StackBlitz](https://stackblitz.com), or a new GitHub repository, so it can be opened in the browser.\n        </details>\n\n        Starter template: [fork this template on StackBlitz](https://stackblitz.com/edit/node-guv65j?file=webpack.config.js&view=editor) (Delete everything unnecessary)\n\n        The _smaller_ the reproduction, the _faster_ others can help you.\n\n  - type: input\n    attributes:\n      label: Minimal reproduction URL\n      placeholder: https://stackblitz.com/edit/...\n    validations:\n      required: true\n\n  - type: markdown\n    attributes:\n      value: |\n        > **🙋 Need help?**\n        >\n        > Get personalized help through my [_Priority Support_ service](https://github.com/sponsors/privatenumber).\n        > From minimal reproduction creation to debugging, I'm happy to assist you!\n\n  - type: markdown\n    attributes:\n      value: \"## 🌍 Environment\"\n\n  - type: input\n    attributes:\n      label: Version\n      placeholder: v0.0.0\n    validations:\n      required: true\n\n  - type: input\n    attributes:\n      label: Node.js version\n      placeholder: v0.0.0\n    validations:\n      required: true\n\n  - type: dropdown\n    id: package-manager\n    attributes:\n      label: Package manager\n      options:\n        - npm\n        - yarn\n        - pnpm\n        - bun\n        - N/A\n    validations:\n      required: true\n\n  - type: dropdown\n    attributes:\n      label: Operating system\n      options:\n        - macOS\n        - Windows\n        - Linux\n    validations:\n      required: true\n\n  - type: markdown\n    attributes:\n      value: |\n        ## 🛠️ Contribute\n        It would be amazing if you can contribute to the project! This project is open source, free to use, and maintained by volunteers. This could be a great opportunity to give back and improve the project for everyone, including yourself.\n\n  - type: checkboxes\n    attributes:\n      label: Contributions\n      options:\n        - label: I plan to open a pull request for this issue\n        - label: I plan to make a financial contribution to this project\n\n  - type: markdown\n    attributes:\n      value: |\n        ## 🚀 Need immediate attention?\n        Escalate this issue by becoming a [_Priority Patron_ sponsor](https://github.com/sponsors/privatenumber)! As a _Priority Patron_, your concern will receive prompt attention, ensuring faster and more efficient resolution.\n\n        [👉 Become a _Priority Patron_ now!](https://github.com/sponsors/privatenumber)\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: 💬 Help / Questions / Discussions\n    url: https://github.com/privatenumber/esbuild-loader/discussions\n    about: Use GitHub Discussions for anything else\n\n  - name: 🚀 Priority Support\n    url: https://github.com/sponsors/privatenumber/\n    about: Need help? Get prioritized help for all your questions and issues\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature-request.yml",
    "content": "name: 🌟 Feature request\ndescription: Have a great idea for this project? Tell us more!\nlabels: [enhancement, pending triage]\nbody:\n  - type: markdown\n    attributes:\n      value: |\n        > 💁‍♂️ Please remember others are volunteering to help you for free, and put in your best effort to follow this form.\n\n        ## 👀 Tell us about your idea\n\n  - type: textarea\n    attributes:\n      label: Feature request\n      description: A clear and concise description of the feature.\n      placeholder: |\n        I would love to be able to...\n    validations:\n      required: true\n\n  - type: textarea\n    attributes:\n      label: Motivations\n      description: |\n        Describe the problem you’re tackling with this feature request.\n      placeholder: |\n        How did you come across this idea?\n    validations:\n      required: true\n\n  - type: textarea\n    attributes:\n      label: Alternatives\n      description: |\n        Have you considered alternative solutions? Is there a workaround?\n      placeholder: |\n        Do you have alternative proposals?\n\n        Are there workarounds?\n\n  - type: textarea\n    attributes:\n      label: Additional context\n      description: |\n        Anything else to share? Screenshots? Links?\n\n  - type: markdown\n    attributes:\n      value: |\n        > **🙋 Experiencing a challenging problem and need expert assistance?**\n        >\n        > Get personalized help through my [_Priority Support_ service](https://github.com/sponsors/privatenumber). From debugging to implementation, I'm here to assist you!\n\n  - type: markdown\n    attributes:\n      value: |\n        ## 🛠️ Contribute\n        It would be amazing if you can contribute to the project! This project is open source, free to use, and maintained by volunteers. This could be a great opportunity to give back and improve the project for everyone, including yourself.\n\n  - type: checkboxes\n    attributes:\n      label: Contributions\n      options:\n        - label: I plan to open a pull request for this issue\n        - label: I plan to make a financial contribution to this project\n\n  - type: markdown\n    attributes:\n      value: |\n        ## 🚀 Need immediate attention?\n        Escalate this issue by becoming a [_Priority Patron_ sponsor](https://github.com/sponsors/privatenumber)! As a _Priority Patron_, your concern will receive prompt attention, ensuring faster and more efficient resolution.\n\n        [👉 Become a _Priority Patron_ now!](https://github.com/sponsors/privatenumber)\n"
  },
  {
    "path": ".github/renovate.json",
    "content": "{\n\t\"$schema\": \"https://docs.renovatebot.com/renovate-schema.json\",\n\t\"extends\": [\n\t\t\"github>privatenumber/renovate-config\"\n\t],\n\t\"packageRules\": [\n\t\t{\n\t\t\t\"description\": \"Pin css-loader to v5 (v6+ dropped Webpack 4 support)\",\n\t\t\t\"matchPackageNames\": [\n\t\t\t\t\"css-loader\"\n\t\t\t],\n\t\t\t\"allowedVersions\": \"<6.0.0\"\n\t\t},\n\t\t{\n\t\t\t\"description\": \"Pin mini-css-extract-plugin to v1 (v2+ dropped Webpack 4 support)\",\n\t\t\t\"matchPackageNames\": [\n\t\t\t\t\"mini-css-extract-plugin\"\n\t\t\t],\n\t\t\t\"allowedVersions\": \"<2.0.0\"\n\t\t},\n\t\t{\n\t\t\t\"description\": \"Pin webpack-cli to v4 (v5+ dropped Webpack 4 support)\",\n\t\t\t\"matchPackageNames\": [\n\t\t\t\t\"webpack-cli\"\n\t\t\t],\n\t\t\t\"allowedVersions\": \"<5.0.0\"\n\t\t}\n\t]\n}\n"
  },
  {
    "path": ".github/workflows/release.yml",
    "content": "name: Release\n\non:\n  push:\n    branches: [master, develop]\n\npermissions:\n  contents: write\n  issues: write\n  pull-requests: write\n  id-token: write\n\njobs:\n  release:\n    name: Release\n    if: (\n      github.repository_owner == 'pvtnbr' && github.ref_name =='develop'\n      ) || (\n      github.repository_owner == 'privatenumber' && github.ref_name =='master'\n      )\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n        with:\n          token: ${{ secrets.GH_TOKEN }}\n\n      - name: Use Node.js\n        uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6\n        with:\n          node-version-file: .nvmrc\n\n      - name: Setup pnpm\n        uses: pnpm/action-setup@v3\n        with:\n          run_install: true\n\n      - name: Prerelease to GitHub\n        if: github.repository_owner == 'pvtnbr'\n        run: |\n          git remote add public https://github.com/$(echo $GITHUB_REPOSITORY | sed \"s/^pvtnbr/privatenumber/\")\n          git fetch public master 'refs/tags/*:refs/tags/*'\n          git push --force --tags origin refs/remotes/public/master:refs/heads/master\n\n          jq '\n              .publishConfig.registry = \"https://npm.pkg.github.com\"\n            | .name = (\"@\" + env.GITHUB_REPOSITORY_OWNER + \"/\" + .name)\n            | .repository = env.GITHUB_REPOSITORY\n            | .release.branches = [\n                \"master\",\n                { name: \"develop\", prerelease: \"rc\", channel: \"latest\" }\n              ]\n            ' package.json > _package.json\n          mv _package.json package.json\n\n      - name: Release\n        env:\n          GH_TOKEN: ${{ secrets.GH_TOKEN }}\n        run: pnpm dlx semantic-release\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "name: Test\non:\n  push:\n    branches: [master, develop]\n  pull_request:\njobs:\n  test:\n    name: Test\n    runs-on: ubuntu-latest\n    timeout-minutes: 10\n\n    steps:\n      - name: Checkout\n        uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6\n\n      - name: Use Node.js\n        uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6\n        with:\n          node-version-file: .nvmrc\n\n      - name: Setup pnpm\n        uses: pnpm/action-setup@v3\n        with:\n          run_install: true\n\n      - name: Lint\n        run: pnpm lint\n\n      - name: Type check\n        run: pnpm type-check\n\n      - name: Build\n        run: pnpm build\n\n      - name: Test\n        run: pnpm test\n\n      - name: Test Node.js v16\n        run: pnpm --use-node-version=16.19.0 tsx tests\n"
  },
  {
    "path": ".gitignore",
    "content": "# Mac OS X\n.DS_Store\n\n# Logs\nlogs\n*.log\nnpm-debug.log*\n\n# Dependency directories\nnode_modules/\n\n# Optional npm cache directory\n.npm\n\n# Optional REPL history\n.node_repl_history\n\n# Output of 'npm pack'\n*.tgz\n\n# Distribution files\ndist\n\n# Cache\n.eslintcache\n\n# Agent skills from npm packages (managed by skills-npm)\n**/skills/npm-*\n"
  },
  {
    "path": ".npmrc",
    "content": "shell-emulator=true\n"
  },
  {
    "path": ".nvmrc",
    "content": "v24.11.0\n"
  },
  {
    "path": ".vscode/settings.json",
    "content": "{\n\t\"typescript.tsdk\": \"node_modules/typescript/lib\",\n}\n"
  },
  {
    "path": "LICENSE",
    "content": "MIT License\n\nCopyright (c) Hiroki Osame <hiroki.osame@gmail.com>\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n"
  },
  {
    "path": "README.md",
    "content": "<h2 align=\"center\">\n    <img width=\"150\" src=\".github/logo.svg\">\n    <br>\n    esbuild-loader\n    <br><br>\n<a href=\"https://npm.im/esbuild-loader\"><img src=\"https://badgen.net/npm/v/esbuild-loader\"></a> <a href=\"https://npm.im/esbuild-loader\"><img src=\"https://badgen.net/npm/dm/esbuild-loader\"></a> <a href=\"https://packagephobia.now.sh/result?p=esbuild-loader\"><img src=\"https://packagephobia.now.sh/badge?p=esbuild-loader\"></a>\n</h2>\n\nSpeed up your Webpack build with [esbuild](https://github.com/evanw/esbuild)! 🔥\n\n[_esbuild_](https://github.com/evanw/esbuild) is a JavaScript bundler written in Go that supports blazing fast ESNext & TypeScript transpilation and [JS minification](https://github.com/privatenumber/minification-benchmarks/).\n\n[_esbuild-loader_](https://github.com/privatenumber/esbuild-loader) lets you harness the speed of esbuild in your Webpack build by offering faster alternatives for transpilation (eg. `babel-loader`/`ts-loader`) and minification (eg. Terser)!\n\n> [!TIP]\n> **Are you using TypeScript with Node.js?**\n>\n> Supercharge your Node.js with TypeScript support using _tsx_!\n> \n> _tsx_ is a simple, lightweight, and blazing fast alternative to ts-node.\n>\n> [→ Learn more about _tsx_](https://github.com/privatenumber/tsx)\n\n<br>\n\n<p align=\"center\">\n\t<a href=\"https://github.com/sponsors/privatenumber/sponsorships?tier_id=398771\"><img width=\"412\" src=\"https://raw.githubusercontent.com/privatenumber/sponsors/master/banners/assets/donate.webp\"></a>\n\t<a href=\"https://github.com/sponsors/privatenumber/sponsorships?tier_id=397608\"><img width=\"412\" src=\"https://raw.githubusercontent.com/privatenumber/sponsors/master/banners/assets/sponsor.webp\"></a>\n</p>\n<p align=\"center\"><sup><i>Already a sponsor?</i> Join the discussion in the <a href=\"https://github.com/pvtnbr/esbuild-loader\">Development repo</a>!</sup></p>\n\n## 🚀 Install\n\n```bash\nnpm i -D esbuild-loader\n```\n\n## 🚦 Quick Setup\n\nTo leverage `esbuild-loader` in your Webpack configuration, add a new rule for `esbuild-loader` matching the files you want to transform, such as `.js`, `.jsx`, `.ts`, or `.tsx`. Make sure to remove any other loaders you were using before (e.g. `babel-loader`/`ts-loader`).\n\nHere's an example of how to set it up in your `webpack.config.js`:\n\n```diff\n  module.exports = {\n      module: {\n          rules: [\n-             // Transpile JavaScript\n-             {\n-                 test: /\\.js$/,\n-                 use: 'babel-loader'\n-             },\n-\n-             // Compile TypeScript\n-             {\n-                 test: /\\.tsx?$/,\n-                 use: 'ts-loader'\n-             },\n+             // Use esbuild to compile JavaScript & TypeScript\n+             {\n+                 // Match `.js`, `.jsx`, `.ts` or `.tsx` files\n+                 test: /\\.[jt]sx?$/,\n+                 loader: 'esbuild-loader',\n+                 options: {\n+                     // JavaScript version to compile to\n+                     target: 'es2015'\n+                 }\n+             },\n\n              // Other rules...\n          ],\n      },\n  }\n```\n\nIn this setup, esbuild will automatically determine how to handle each file based on its extension:\n- `.js` files will be treated as JS (no JSX allowed)\n- `.jsx` as JSX\n- `.ts` as TS (no TSX allowed)\n- `.tsx` as TSX\n\n\nIf you want to force a specific loader on different file extensions (e.g. to allow JSX in `.js` files), you can use the [`loader` option](https://github.com/privatenumber/esbuild-loader/#loader):\n\n```diff\n {\n     test: /\\.js$/,\n     loader: 'esbuild-loader',\n     options: {\n+        // Treat `.js` files as `.jsx` files\n+        loader: 'jsx',\n\n         // JavaScript version to transpile to\n         target: 'es2015'\n     }\n }\n```\n\n\n## Loader\n\n### JavaScript\n\n`esbuild-loader` can be used in-place of `babel-loader` to transpile new JavaScript syntax into code compatible with older JavaScript engines.\n\nWhile this ensures your code can run smoothly across various environments, note that it can bloat your output code (like Babel).\n\nThe default target is `esnext`, which means it doesn't perform any transpilations.\n\nTo specify a target JavaScript engine that only supports ES2015, use the following configuration in your `webpack.config.js`:\n\n```diff\n {\n     test: /\\.jsx?$/,\n     loader: 'esbuild-loader',\n     options: {\n+        target: 'es2015',\n     },\n }\n```\n\nFor a detailed list of supported transpilations and versions, refer to [the esbuild documentation](https://esbuild.github.io/content-types/#javascript).\n\n### TypeScript\n\n`esbuild-loader` can be used in-place of `ts-loader` to compile TypeScript.\n\n```js\n({\n    // `.ts` or `.tsx` files\n    test: /\\.tsx?$/,\n    loader: 'esbuild-loader'\n})\n```\n\n\n> [!IMPORTANT]\n> It's possible to use `loader: 'tsx'` for both `.ts` and `.tsx` files, but this could lead to unexpected behavior as TypeScript and TSX do not have compatible syntaxes.\n>\n> [→ Read more](https://esbuild.github.io/content-types/#ts-vs-tsx)\n\n#### `tsconfig.json`\nIf you have a `tsconfig.json` file in your project, `esbuild-loader` will automatically load it.\n\nIf it's under a custom name, you can pass in the path via `tsconfig` option:\n```diff\n {\n     test: /\\.tsx?$/,\n     loader: 'esbuild-loader',\n     options: {\n+        tsconfig: './tsconfig.custom.json',\n     },\n },\n```\n\n> Behind the scenes: [`get-tsconfig`](https://github.com/privatenumber/get-tsconfig) is used to load the tsconfig, and to also resolve the `extends` property if it exists.\n\nThe `tsconfigRaw` option can be used to pass in a raw `tsconfig` object, but it will not resolve the `extends` property.\n\n\n##### Caveats\n- esbuild only supports a subset of `tsconfig` options [(see `TransformOptions` interface)](https://github.com/evanw/esbuild/blob/88821b7e7d46737f633120f91c65f662eace0bcf/lib/shared/types.ts#L159-L165).\n\n- Enable [`isolatedModules`](https://www.typescriptlang.org/tsconfig#isolatedModules) to avoid mis-compilation with features like re-exporting types.\n\n- Enable [`esModuleInterop`](https://www.typescriptlang.org/tsconfig/#esModuleInterop) to make TypeScript's type system compatible with ESM imports.\n\n- Features that require type interpretation, such as `emitDecoratorMetadata` and declaration, are not supported.\n\n[→ Read more about TypeScript Caveats](https://esbuild.github.io/content-types/#typescript-caveats)\n\n#### `tsconfig.json` Paths\nUse [tsconfig-paths-webpack-plugin](https://github.com/dividab/tsconfig-paths-webpack-plugin) to add support for [`tsconfig.json#paths`](https://www.typescriptlang.org/tsconfig/paths.html).\n\nSince `esbuild-loader` only transforms code, it cannot aid Webpack with resolving paths.\n\n\n#### Type-checking\n\nesbuild **does not** type check your code. And according to the [esbuild FAQ](https://esbuild.github.io/faq/#:~:text=typescript%20type%20checking%20(just%20run%20tsc%20separately)), it will not be supported.\n\nConsider these type-checking alternatives:\n- Using an IDEs like [VSCode](https://code.visualstudio.com/docs/languages/typescript) or [WebStorm](https://www.jetbrains.com/help/webstorm/typescript-support.html) that has live type-checking built in\n- Running `tsc --noEmit` to type check\n- Integrating type-checking to your Webpack build as a separate process using [`fork-ts-checker-webpack-plugin`](https://github.com/TypeStrong/fork-ts-checker-webpack-plugin)\n\n### Defining constants\n\nUse the [`define`](#define) option to replace global identifiers with constant expressions:\n\n```diff\n {\n     test: /\\.[jt]sx?$/,\n     loader: 'esbuild-loader',\n     options: {\n+        define: {\n+            'process.env.NODE_ENV': JSON.stringify('production'),\n+        },\n     },\n }\n```\n\n> [!TIP]\n> The loader's `define` works with **all devtools**, including eval-based ones. If you're using the [plugin's `define`](#defining-constants-1) and it's not working, try the loader instead.\n\n## EsbuildPlugin\n\n### Minification\nEsbuild supports JavaScript minification, offering a faster alternative to traditional JS minifiers like Terser or UglifyJs. Minification is crucial for reducing file size and improving load times in web development. For a comparative analysis of its performance, refer to these [minification benchmarks](https://github.com/privatenumber/minification-benchmarks).\n\nIn `webpack.config.js`:\n\n```diff\n+ const { EsbuildPlugin } = require('esbuild-loader')\n\n  module.exports = {\n      ...,\n\n+     optimization: {\n+         minimizer: [\n+             new EsbuildPlugin({\n+                 target: 'es2015'  // Syntax to transpile to (see options below for possible values)\n+             })\n+         ]\n+     },\n  }\n```\n\n> [!TIP]\n> Utilizing the `target` option allows for the use of newer JavaScript syntax, enhancing minification effectiveness.\n\n### Defining constants\n\nWebpack's [`DefinePlugin`](https://webpack.js.org/plugins/define-plugin/) can replaced with `EsbuildPlugin` to define global constants. This could speed up the build by removing the parsing costs associated with the `DefinePlugin`.\n\nIn `webpack.config.js`:\n\n```diff\n- const { DefinePlugin } = require('webpack')\n+ const { EsbuildPlugin } = require('esbuild-loader')\n\n  module.exports = {\n      // ...,\n\n      plugins:[\n-         new DefinePlugin({\n-             'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),\n-         })\n+         new EsbuildPlugin({\n+             define: {\n+                 'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),\n+             },\n+         }),\n      ]\n  }\n```\n\n> [!WARNING]\n> The plugin's `define` option **does not work with eval-based devtools** (e.g., `eval`, `eval-source-map`). This is because eval devtools wrap module code in `eval()` strings, and esbuild's define cannot replace identifiers inside string literals. If you need to use `define` with eval devtools, use the [loader's `define` option](#define) instead, which transforms files before bundling.\n\n### Transpilation\n\nIf your project does not use TypeScript, JSX, or any other syntax that requires additional configuration beyond what Webpack provides, you can use `EsbuildPlugin` for transpilation instead of the loader.\n\nIt will be faster because there's fewer files to process, and will produce a smaller output because polyfills will only be added once for the entire build as opposed to per file.\n\nTo utilize esbuild for transpilation, simply set the `target` option on the plugin to specify which syntax support you want.\n\n\n## CSS Minification\n\nDepending on your setup, there are two ways to minify CSS. You should already have CSS loading setup using [`css-loader`](https://github.com/webpack-contrib/css-loader).\n\n### CSS assets\nIf the CSS is extracted and emitted as `.css` file, you can replace CSS minification plugins like [`css-minimizer-webpack-plugin`](https://github.com/webpack-contrib/css-minimizer-webpack-plugin) with the `EsbuildPlugin`.\n\nAssuming the CSS is extracted using something like [MiniCssExtractPlugin](https://github.com/webpack-contrib/mini-css-extract-plugin), in `webpack.config.js`:\n\n```diff\n  const { EsbuildPlugin } = require('esbuild-loader')\n  const MiniCssExtractPlugin = require('mini-css-extract-plugin');\n\n  module.exports = {\n      // ...,\n\n      optimization: {\n          minimizer: [\n              new EsbuildPlugin({\n                  target: 'es2015',\n+                 css: true  // Apply minification to CSS assets\n              })\n          ]\n      },\n\n      module: {\n          rules: [\n              {\n                  test: /\\.css$/i,\n                  use: [\n                      MiniCssExtractPlugin.loader,\n                      'css-loader'\n                  ]\n              }\n          ],\n      },\n\n      plugins: [\n          new MiniCssExtractPlugin()\n      ]\n  }\n```\n\n\n### CSS in JS\n\nIf your CSS is not emitted as a `.css` file, but rather injected with JavaScript using something like [`style-loader`](https://github.com/webpack-contrib/style-loader), you can use the loader for minification.\n\n\nIn `webpack.config.js`:\n\n```diff\n  module.exports = {\n      // ...,\n\n      module: {\n          rules: [\n              {\n                  test: /\\.css$/i,\n                  use: [\n                      'style-loader',\n                      'css-loader',\n+                     {\n+                         loader: 'esbuild-loader',\n+                         options: {\n+                             minify: true,\n+                         },\n+                     },\n                  ],\n              },\n          ],\n      },\n  }\n```\n\n## Bring your own esbuild (Advanced)\n\nesbuild-loader comes with a version of esbuild it has been tested to work with. However, [esbuild has a frequent release cadence](https://github.com/evanw/esbuild/releases), and while we try to keep up with the important releases, it can get outdated.\n\nTo work around this, you can use the `implementation` option in the loader or the plugin to pass in your own version of esbuild (eg. a newer one).\n\n> [!WARNING]  \n> ⚠esbuild is not stable yet and can have dramatic differences across releases. Using a different version of esbuild is not guaranteed to work.\n\n\n```diff\n+ const esbuild = require('esbuild')\n\n  module.exports = {\n      // ...,\n\n      module: {\n          rules: [\n              {\n                  test: ...,\n                  loader: 'esbuild-loader',\n                  options: {\n                      // ...,\n+                     implementation: esbuild,\n                  },\n              },\n          ],\n      },\n  }\n```\n\n## Setup examples\nIf you'd like to see working Webpack builds that use esbuild-loader for basic JS, React, TypeScript, Next.js, etc. check out the examples repo:\n\n[→ esbuild-loader examples](https://github.com/privatenumber/esbuild-loader-examples)\n\n## ⚙️ Options\n\n### Loader\nThe loader supports [all Transform options from esbuild](https://github.com/evanw/esbuild/blob/88821b7e7d46737f633120f91c65f662eace0bcf/lib/shared/types.ts#L158-L172).\n\nNote:\n- Source-maps are automatically configured for you via [`devtool`](https://webpack.js.org/configuration/devtool/).  `sourcemap`/`sourcefile` options are ignored.\n- The root `tsconfig.json` is automatically detected for you. You don't need to pass in [`tsconfigRaw`](https://esbuild.github.io/api/#tsconfig-raw) unless it's in a different path.\n\n\nHere are some common configurations and custom options:\n\n#### tsconfig\n\nType: `string`\n\nPass in the file path to a **custom** tsconfig file. If the file name is `tsconfig.json`, it will automatically detect it.\n\n#### target\nType: `string | Array<string>`\n\nDefault: `'es2015'`\n\nThe target environment (e.g. `es2016`, `chrome80`, `esnext`).\n\nRead more about it in the [esbuild docs](https://esbuild.github.io/api/#target).\n\n#### loader\nType: `'js' | 'jsx' | 'ts' | 'tsx' | 'css' | 'json' | 'text' | 'base64' | 'file' | 'dataurl' | 'binary' | 'default'`\n\nDefault: `'default'`\n\nThe loader to use to handle the file. See the type for [possible values](https://github.com/evanw/esbuild/blob/88821b7e7d46737f633120f91c65f662eace0bcf/lib/shared/types.ts#L3).\n\nBy default, it automatically detects the loader based on the file extension.\n\nRead more about it in the [esbuild docs](https://esbuild.github.io/api/#loader).\n\n#### jsxFactory\nType: `string`\n\nDefault: `React.createElement`\n\nCustomize the JSX factory function name to use.\n\nRead more about it in the [esbuild docs](https://esbuild.github.io/api/#jsx-factory).\n\n#### jsxFragment\nType: `string`\n\nDefault: `React.Fragment`\n\nCustomize the JSX fragment function name to use.\n\n\nRead more about it in the [esbuild docs](https://esbuild.github.io/api/#jsx-fragment).\n\n#### define\nType: `{ [key: string]: string }`\n\nReplace global identifiers with constant expressions (e.g., `'process.env.NODE_ENV': JSON.stringify('production')`).\n\n> [!TIP]\n> Unlike the plugin's `define` option, the loader's `define` works with **all devtools** including eval-based ones (e.g., `eval-source-map`). This is because the loader transforms files _before_ Webpack bundles them, so identifiers are replaced before any eval wrapping occurs.\n\nRead more about it in the [esbuild docs](https://esbuild.github.io/api/#define).\n\n#### implementation\nType: `{ transform: Function }`\n\n_Custom esbuild-loader option._\n\nUse it to pass in a [different esbuild version](#bring-your-own-esbuild-advanced).\n\n### EsbuildPlugin\n\nThe loader supports [all Transform options from esbuild](https://github.com/evanw/esbuild/blob/88821b7e7d46737f633120f91c65f662eace0bcf/lib/shared/types.ts#L158-L172).\n\n#### target\nType: `string | Array<string>`\n\nDefault: `'esnext'`\n\nTarget environment (e.g. `'es2016'`, `['chrome80', 'esnext']`)\n\nRead more about it in the [esbuild docs](https://esbuild.github.io/api/#target).\n\nHere are some common configurations and custom options:\n\n#### format\nType: `'iife' | 'cjs' | 'esm'`\n\nDefault:\n  - `iife` if both of these conditions are met:\n    - Webpack's [`target`](https://webpack.js.org/configuration/target/) is set to `web`\n    - esbuild's [`target`](#target-1) is not `esnext`\n  - `undefined` (no format conversion) otherwise\n\nThe default is `iife` when esbuild is configured to support a low target, because esbuild injects helper functions at the top of the code. On the web, having functions declared at the top of a script can pollute the global scope. In some cases, this can lead to a variable collision error. By setting `format: 'iife'`, esbuild wraps the helper functions in an [IIFE](https://developer.mozilla.org/en-US/docs/Glossary/IIFE) to prevent them from polluting the global.\n\nRead more about it in the [esbuild docs](https://esbuild.github.io/api/#format).\n\n#### minify\nType: `boolean`\n\nDefault: `true`\n\nEnable JS minification. Enables all `minify*` flags below.\n\nTo have nuanced control over minification, disable this and enable the specific minification you want below.\n\nRead more about it in the [esbuild docs](https://esbuild.github.io/api/#minify).\n\n#### minifyWhitespace\nType: `boolean`\n\nMinify JS by removing whitespace.\n\n#### minifyIdentifiers\nType: `boolean`\n\nMinify JS by shortening identifiers.\n\n#### minifySyntax\nType: `boolean`\n\nMinify JS using equivalent but shorter syntax.\n\n#### legalComments\nType: `'none' | 'inline' | 'eof' | 'external'`\n\nDefault: `'inline'`\n\nRead more about it in the [esbuild docs](https://esbuild.github.io/api/#legal-comments).\n\n#### css\nType: `boolean`\n\nDefault: `false`\n\nWhether to minify CSS files.\n\n#### include\nType: `string | RegExp | Array<string | RegExp>`\n\nTo only apply the plugin to certain assets, pass in filters include\n\n#### exclude\nType: `string | RegExp | Array<string | RegExp>`\n\nTo prevent the plugin from applying to certain assets, pass in filters to exclude\n\n#### implementation\nType: `{ transform: Function }`\n\nUse it to pass in a [different esbuild version](#bring-your-own-esbuild-advanced).\n\n## 💡 Support\n\nFor personalized assistance, take advantage of my [_Priority Support_ service](https://github.com/sponsors/privatenumber).\n\nWhether it's about Webpack configuration, esbuild, or TypeScript, I'm here to guide you every step of the way!\n\n## 🙋‍♀️ FAQ\n\n### Is it possible to use esbuild plugins?\nNo. esbuild plugins are [only available in the build API](https://esbuild.github.io/plugins/#:~:text=plugins%20can%20also%20only%20be%20used%20with%20the%20build%20api%2C%20not%20with%20the%20transform%20api.). And esbuild-loader uses the transform API instead of the build API for two reasons:\n1. The build API is for creating JS bundles, which is what Webpack does. If you want to use esbuild's build API, consider using esbuild directly instead of Webpack.\n\n2. The build API reads directly from the file-system, but Webpack loaders operate in-memory. Webpack loaders are essentially just functions that are called with the source-code as the input. Not reading from the file-system allows loaders to be chainable. For example, using `vue-loader` to compile Single File Components (`.vue` files), then using `esbuild-loader` to transpile just the JS part of the SFC.\n\n### Is it possible to use esbuild's [inject](https://esbuild.github.io/api/#inject) option?\n\nNo. The `inject` option is only available in the build API. And esbuild-loader uses the transform API.\n\nHowever, you can use the Webpack equivalent [ProvidePlugin](https://webpack.js.org/plugins/provide-plugin/) instead.\n\nIf you're using React, check out [this example](https://github.com/privatenumber/esbuild-loader-examples/blob/52ca91b8cb2080de5fc63cc6e9371abfefe1f823/examples/react/webpack.config.js#L39-L41) on how to auto-import React in your components.\n\n### Is it possible to use Babel plugins?\nNo. If you really need them, consider porting them over to a Webpack loader.\n\nAnd please don't chain `babel-loader` and `esbuild-loader`. The speed gains come from replacing `babel-loader`.\n\n### Why am I not getting a [100x speed improvement](https://esbuild.github.io/faq/#benchmark-details) as advertised?\nRunning esbuild as a standalone bundler vs esbuild-loader + Webpack are completely different:\n- esbuild is highly optimized, written in Go, and compiled to native code. Read more about it [here](https://esbuild.github.io/faq/#why-is-esbuild-fast).\n- esbuild-loader is handled by Webpack in a JS runtime, which applies esbuild transforms per file. On top of that, there's likely other loaders & plugins in a Webpack config that slow it down.\n\nUsing a JS runtime introduces a bottleneck that makes reaching those speeds impossible. However, esbuild-loader can still speed up your build by removing the bottlenecks created by [`babel-loader`](https://twitter.com/wSokra/status/1316274855042584577), `ts-loader`, Terser, etc.\n\n\n## 💞 Related projects\n\n#### [tsx](https://github.com/esbuild-kit/tsx)\nNode.js enhanced with esbuild to run TypeScript and ESM.\n\n#### [instant-mocha](https://github.com/privatenumber/instant-mocha)\nWebpack-integrated Mocha test-runner with Webpack 5 support.\n\n#### [webpack-localize-assets-plugin](https://github.com/privatenumber/webpack-localize-assets-plugin)\nLocalize/i18nalize your Webpack build. Optimized for multiple locales!\n\n## Sponsors\n\n<p align=\"center\">\n\t<a href=\"https://github.com/sponsors/privatenumber\">\n\t\t<img src=\"https://cdn.jsdelivr.net/gh/privatenumber/sponsors/sponsorkit/sponsors.svg\">\n\t</a>\n</p>\n\n"
  },
  {
    "path": "package.json",
    "content": "{\n\t\"name\": \"esbuild-loader\",\n\t\"version\": \"0.0.0-semantic-release\",\n\t\"description\": \"⚡️ Speed up your Webpack build with esbuild\",\n\t\"keywords\": [\n\t\t\"esbuild\",\n\t\t\"webpack\",\n\t\t\"loader\",\n\t\t\"typescript\",\n\t\t\"esnext\"\n\t],\n\t\"license\": \"MIT\",\n\t\"repository\": \"privatenumber/esbuild-loader\",\n\t\"funding\": \"https://github.com/privatenumber/esbuild-loader?sponsor=1\",\n\t\"author\": {\n\t\t\"name\": \"Hiroki Osame\",\n\t\t\"email\": \"hiroki.osame@gmail.com\"\n\t},\n\t\"files\": [\n\t\t\"dist\"\n\t],\n\t\"type\": \"module\",\n\t\"main\": \"./dist/index.cjs\",\n\t\"types\": \"./dist/index.d.cts\",\n\t\"exports\": {\n\t\t\".\": {\n\t\t\t\"types\": \"./dist/index.d.cts\",\n\t\t\t\"default\": \"./dist/index.cjs\"\n\t\t},\n\t\t\"./package.json\": \"./package.json\"\n\t},\n\t\"imports\": {\n\t\t\"#esbuild-loader\": {\n\t\t\t\"types\": \"./src/index.d.ts\",\n\t\t\t\"development\": \"./src/index.ts\",\n\t\t\t\"default\": \"./dist/index.cjs\"\n\t\t}\n\t},\n\t\"packageManager\": \"pnpm@10.26.1\",\n\t\"scripts\": {\n\t\t\"build\": \"pkgroll --target=node16.19.0\",\n\t\t\"test\": \"tsx --env-file=.env tests\",\n\t\t\"dev\": \"tsx watch --env-file=.env --conditions=development tests\",\n\t\t\"lint\": \"lintroll --cache .\",\n\t\t\"type-check\": \"tsc --noEmit\",\n\t\t\"prepack\": \"pnpm build && clean-pkg-json\",\n\t\t\"prepare\": \"skills-npm\"\n\t},\n\t\"dependencies\": {\n\t\t\"esbuild\": \"^0.27.1\",\n\t\t\"get-tsconfig\": \"^4.10.1\",\n\t\t\"loader-utils\": \"^2.0.4\",\n\t\t\"webpack-sources\": \"^3.3.4\"\n\t},\n\t\"peerDependencies\": {\n\t\t\"webpack\": \"^4.40.0 || ^5.0.0\"\n\t},\n\t\"devDependencies\": {\n\t\t\"@types/loader-utils\": \"^2.0.6\",\n\t\t\"@types/mini-css-extract-plugin\": \"2.4.0\",\n\t\t\"@types/node\": \"^22.19.3\",\n\t\t\"@types/webpack\": \"^4.41.40\",\n\t\t\"@types/webpack-sources\": \"^3.2.3\",\n\t\t\"clean-pkg-json\": \"^1.3.0\",\n\t\t\"css-loader\": \"^5.2.7\",\n\t\t\"execa\": \"^8.0.1\",\n\t\t\"fs-fixture\": \"^2.11.0\",\n\t\t\"lintroll\": \"^1.20.1\",\n\t\t\"manten\": \"^2.0.0\",\n\t\t\"memfs\": \"^4.56.11\",\n\t\t\"mini-css-extract-plugin\": \"^1.6.2\",\n\t\t\"pkgroll\": \"^2.17.0\",\n\t\t\"skills-npm\": \"^1.0.0\",\n\t\t\"tsx\": \"^4.20.6\",\n\t\t\"typescript\": \"^5.9.3\",\n\t\t\"webpack\": \"^4.47.0\",\n\t\t\"webpack-cli\": \"^4.10.0\",\n\t\t\"webpack-merge\": \"^6.0.1\",\n\t\t\"webpack-test-utils\": \"^2.1.0\",\n\t\t\"webpack5\": \"npm:webpack@^5.0.0\"\n\t},\n\t\"pnpm\": {\n\t\t\"overrides\": {\n\t\t\t\"fsevents@1\": \"^2.0.0\"\n\t\t}\n\t}\n}\n"
  },
  {
    "path": "src/@types/webpack-module-filename-helpers.d.ts",
    "content": "declare module 'webpack/lib/ModuleFilenameHelpers.js' {\n\ttype Filter = string | RegExp;\n\ttype FilterObject = {\n\t\ttest?: Filter | Filter[];\n\t\tinclude?: Filter | Filter[];\n\t\texclude?: Filter | Filter[];\n\t};\n\n\texport const matchObject: (filterObject: FilterObject, stringToCheck: string) => boolean;\n}\n"
  },
  {
    "path": "src/@types/webpack.d.ts",
    "content": "import 'webpack';\nimport type { LoaderContext as Webpack5LoaderContext } from 'webpack5';\n\ndeclare module 'webpack' {\n\n\tnamespace compilation {\n\t\tinterface Compilation {\n\t\t\tgetAssets(): Asset[];\n\t\t\temitAsset(\n\t\t\t\tfile: string,\n\t\t\t\tsource: Source,\n\t\t\t\tassetInfo?: AssetInfo,\n\t\t\t): void;\n\t\t}\n\t}\n\n\tnamespace loader {\n\t\tinterface LoaderContext <T> {\n\t\t\tgetOptions: Webpack5LoaderContext<T>['getOptions'];\n\t\t}\n\t}\n\n\tinterface AssetInfo {\n\t\tminimized?: boolean;\n\t}\n}\n"
  },
  {
    "path": "src/index.d.ts",
    "content": "import type { EsbuildPluginOptions } from './types.js';\n\nexport class EsbuildPlugin {\n\tconstructor(options?: EsbuildPluginOptions);\n\n\tapply(): void;\n}\n\nexport * from './types.js';\n"
  },
  {
    "path": "src/index.ts",
    "content": "import esbuildLoader from './loader.js';\nimport EsbuildPlugin from './plugin.js';\n\nexport default esbuildLoader;\nexport { EsbuildPlugin };\n"
  },
  {
    "path": "src/loader.ts",
    "content": "import path from 'path';\nimport {\n\ttransform as defaultEsbuildTransform,\n\ttype TransformOptions,\n} from 'esbuild';\nimport { getOptions } from 'loader-utils';\nimport type webpack from 'webpack';\nimport {\n\tgetTsconfig,\n\tparseTsconfig,\n\ttype TsConfigResult,\n} from 'get-tsconfig';\nimport type { LoaderOptions } from './types.js';\n\nconst tsconfigCache = new Map<string, TsConfigResult>();\n\nconst tsExtensionsPattern = /\\.(?:[cm]?ts|[tj]sx)$/;\n\nasync function ESBuildLoader(\n\tthis: webpack.loader.LoaderContext<LoaderOptions>,\n\tsource: string,\n): Promise<void> {\n\tconst done = this.async()!;\n\tconst options: LoaderOptions = typeof this.getOptions === 'function' ? this.getOptions() : getOptions(this);\n\tconst {\n\t\timplementation,\n\t\ttsconfig: tsconfigPath,\n\t\t...esbuildTransformOptions\n\t} = options;\n\n\tif (implementation && typeof implementation.transform !== 'function') {\n\t\tdone(\n\t\t\tnew TypeError(\n\t\t\t\t`esbuild-loader: options.implementation.transform must be an ESBuild transform function. Received ${typeof implementation.transform}`,\n\t\t\t),\n\t\t);\n\t\treturn;\n\t}\n\tconst transform = implementation?.transform ?? defaultEsbuildTransform;\n\n\tconst { resourcePath } = this;\n\tconst transformOptions = {\n\t\t...esbuildTransformOptions,\n\t\ttarget: options.target ?? 'es2015',\n\t\tloader: options.loader ?? 'default',\n\t\tsourcemap: this.sourceMap,\n\t\tsourcefile: resourcePath,\n\t};\n\n\tconst isDependency = resourcePath.includes(`${path.sep}node_modules${path.sep}`);\n\tif (\n\t\t!('tsconfigRaw' in transformOptions)\n\n\t\t// If file is local project, always try to apply tsconfig.json (e.g. allowJs)\n\t\t// If file is dependency, only apply tsconfig.json if .ts\n\t\t&& (!isDependency || tsExtensionsPattern.test(resourcePath))\n\t) {\n\t\t/**\n\t\t * If a tsconfig.json path is specified, force apply it\n\t\t * Same way a provided tsconfigRaw is applied regardless\n\t\t * of whether it actually matches\n\t\t *\n\t\t * This follows TypeScript behavior: a tsconfig applies to all\n\t\t * files imported by entry files, not just files matching include patterns.\n\t\t * The include/files patterns only determine entry points.\n\t\t */\n\t\tif (!isDependency && tsconfigPath) {\n\t\t\tconst tsconfigFullPath = path.resolve(tsconfigPath);\n\t\t\tconst cacheKey = `esbuild-loader:${tsconfigFullPath}`;\n\t\t\tlet tsconfig = tsconfigCache.get(cacheKey);\n\t\t\tif (!tsconfig) {\n\t\t\t\ttsconfig = {\n\t\t\t\t\tconfig: parseTsconfig(tsconfigFullPath),\n\t\t\t\t\tpath: tsconfigFullPath,\n\t\t\t\t};\n\t\t\t\ttsconfigCache.set(cacheKey, tsconfig);\n\t\t\t}\n\n\t\t\ttransformOptions.tsconfigRaw = tsconfig.config as TransformOptions['tsconfigRaw'];\n\t\t} else {\n\t\t\t/* Detect tsconfig file */\n\n\t\t\tlet tsconfig;\n\n\t\t\ttry {\n\t\t\t\t// Webpack shouldn't be loading the same path multiple times so doesn't need to be cached\n\t\t\t\ttsconfig = getTsconfig(resourcePath, 'tsconfig.json');\n\t\t\t} catch (error) {\n\t\t\t\tif (error instanceof Error) {\n\t\t\t\t\tconst tsconfigError = new Error(`[esbuild-loader] Error parsing tsconfig.json:\\n${error.message}`);\n\t\t\t\t\tif (isDependency) {\n\t\t\t\t\t\tthis.emitWarning(tsconfigError);\n\t\t\t\t\t} else {\n\t\t\t\t\t\treturn done(tsconfigError);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (tsconfig) {\n\t\t\t\ttransformOptions.tsconfigRaw = tsconfig.config as TransformOptions['tsconfigRaw'];\n\t\t\t}\n\t\t}\n\t}\n\n\t/**\n\t * Enable dynamic import by default to support code splitting in Webpack\n\t */\n\ttransformOptions.supported = {\n\t\t'dynamic-import': true,\n\t\t...transformOptions.supported,\n\t};\n\n\ttry {\n\t\tconst { code, map } = await transform(source, transformOptions);\n\t\tdone(null, code, map && JSON.parse(map));\n\t} catch (error: unknown) {\n\t\tdone(error as Error);\n\t}\n}\n\nexport default ESBuildLoader;\n"
  },
  {
    "path": "src/plugin.ts",
    "content": "import { transform as defaultEsbuildTransform } from 'esbuild';\nimport {\n\tRawSource as WP4RawSource,\n\tSourceMapSource as WP4SourceMapSource,\n} from 'webpack-sources';\nimport type webpack4 from 'webpack';\nimport type webpack5 from 'webpack5';\nimport ModuleFilenameHelpers from 'webpack/lib/ModuleFilenameHelpers.js';\nimport { version } from '../package.json';\nimport type { EsbuildPluginOptions } from './types.js';\n\ntype Compiler = webpack4.Compiler | webpack5.Compiler;\ntype Compilation = webpack4.compilation.Compilation | webpack5.Compilation;\ntype Asset = webpack4.compilation.Asset | Readonly<webpack5.Asset>;\ntype EsbuildTransform = typeof defaultEsbuildTransform;\n\nconst isJsFile = /\\.[cm]?js(?:\\?.*)?$/i;\nconst isCssFile = /\\.css(?:\\?.*)?$/i;\nconst pluginName = 'EsbuildPlugin';\n\nconst transformAssets = async (\n\toptions: EsbuildPluginOptions,\n\ttransform: EsbuildTransform,\n\tcompilation: Compilation,\n\tuseSourceMap: boolean,\n) => {\n\tconst { compiler } = compilation;\n\tconst sources = 'webpack' in compiler && compiler.webpack.sources;\n\tconst SourceMapSource = (sources ? sources.SourceMapSource : WP4SourceMapSource);\n\tconst RawSource = (sources ? sources.RawSource : WP4RawSource);\n\n\tconst {\n\t\tcss: minifyCss,\n\t\tinclude,\n\t\texclude,\n\t\timplementation,\n\t\t...transformOptions\n\t} = options;\n\n\tconst minimized = (\n\t\ttransformOptions.minify\n\t\t|| transformOptions.minifyWhitespace\n\t\t|| transformOptions.minifyIdentifiers\n\t\t|| transformOptions.minifySyntax\n\t);\n\n\tconst assets = (compilation.getAssets() as Asset[]).filter(asset => (\n\n\t\t// Filter out already minimized\n\t\t!asset.info.minimized\n\n\t\t// Filter out by file type\n\t\t&& (\n\t\t\tisJsFile.test(asset.name)\n\t\t\t|| (minifyCss && isCssFile.test(asset.name))\n\t\t)\n\t\t&& ModuleFilenameHelpers.matchObject(\n\t\t\t{\n\t\t\t\tinclude,\n\t\t\t\texclude,\n\t\t\t},\n\t\t\tasset.name,\n\t\t)\n\t));\n\n\tawait Promise.all(assets.map(async (asset) => {\n\t\tconst assetIsCss = isCssFile.test(asset.name);\n\t\tlet source: string | Buffer | ArrayBuffer;\n\t\tlet map = null;\n\t\tif (useSourceMap) {\n\t\t\tif (asset.source.sourceAndMap) {\n\t\t\t\tconst sourceAndMap = asset.source.sourceAndMap();\n\t\t\t\tsource = sourceAndMap.source;\n\t\t\t\tmap = sourceAndMap.map;\n\t\t\t} else {\n\t\t\t\tsource = asset.source.source();\n\t\t\t\tif (asset.source.map) {\n\t\t\t\t\tmap = asset.source.map();\n\t\t\t\t}\n\t\t\t}\n\t\t} else {\n\t\t\tsource = asset.source.source();\n\t\t}\n\t\tconst sourceAsString = source.toString();\n\t\tconst result = await transform(sourceAsString, {\n\t\t\t...transformOptions,\n\t\t\tloader: (\n\t\t\t\tassetIsCss\n\t\t\t\t\t? 'css'\n\t\t\t\t\t: transformOptions.loader\n\t\t\t),\n\t\t\tsourcemap: useSourceMap,\n\t\t\tsourcefile: asset.name,\n\t\t});\n\n\t\tif (result.legalComments) {\n\t\t\tcompilation.emitAsset(\n\t\t\t\t`${asset.name}.LEGAL.txt`,\n\t\t\t\tnew RawSource(result.legalComments) as webpack5.sources.Source,\n\t\t\t);\n\t\t}\n\n\t\tcompilation.updateAsset(\n\t\t\tasset.name,\n\t\t\t(\n\t\t\t\t// @ts-expect-error complex webpack union type for source\n\t\t\t\tresult.map\n\t\t\t\t\t? new SourceMapSource(\n\t\t\t\t\t\tresult.code,\n\t\t\t\t\t\tasset.name,\n\t\t\t\t\t\tresult.map,\n\t\t\t\t\t\tsourceAsString,\n\t\t\t\t\t\t// @ts-expect-error webpack types use Object, not RawSourceMap\n\t\t\t\t\t\tmap ?? undefined,\n\t\t\t\t\t\ttrue,\n\t\t\t\t\t)\n\t\t\t\t\t: new RawSource(result.code)\n\t\t\t),\n\t\t\t{\n\t\t\t\t...asset.info,\n\t\t\t\tminimized,\n\t\t\t},\n\t\t);\n\t}));\n};\n\nexport default class EsbuildPlugin {\n\toptions: EsbuildPluginOptions;\n\n\tconstructor(\n\t\toptions: EsbuildPluginOptions = {},\n\t) {\n\t\tconst { implementation } = options;\n\t\tif (\n\t\t\timplementation\n\t\t\t&& typeof implementation.transform !== 'function'\n\t\t) {\n\t\t\tthrow new TypeError(\n\t\t\t\t`[${pluginName}] implementation.transform must be an esbuild transform function. Received ${typeof implementation.transform}`,\n\t\t\t);\n\t\t}\n\n\t\tthis.options = options;\n\t}\n\n\tapply(compiler: Compiler) {\n\t\tconst {\n\t\t\timplementation,\n\t\t\t...options\n\t\t} = this.options;\n\t\tconst transform = implementation?.transform ?? defaultEsbuildTransform;\n\n\t\tif (!('format' in options)) {\n\t\t\tconst { target } = compiler.options;\n\t\t\tconst isWebTarget = (\n\t\t\t\tArray.isArray(target)\n\t\t\t\t\t? target.includes('web')\n\t\t\t\t\t: target === 'web'\n\t\t\t);\n\t\t\tconst wontGenerateHelpers = !options.target || (\n\t\t\t\tArray.isArray(options.target)\n\t\t\t\t\t? (\n\t\t\t\t\t\toptions.target.length === 1\n\t\t\t\t\t\t&& options.target[0] === 'esnext'\n\t\t\t\t\t)\n\t\t\t\t\t: options.target === 'esnext'\n\t\t\t);\n\n\t\t\tif (isWebTarget && !wontGenerateHelpers) {\n\t\t\t\toptions.format = 'iife';\n\t\t\t}\n\t\t}\n\n\t\t/**\n\t\t * Enable minification by default if used in the minimizer array\n\t\t * unless further specified in the options\n\t\t */\n\t\tconst usedAsMinimizer = compiler.options.optimization?.minimizer?.includes?.(this);\n\t\tif (\n\t\t\tusedAsMinimizer\n\t\t\t&& !(\n\t\t\t\t'minify' in options\n\t\t\t\t|| 'minifyWhitespace' in options\n\t\t\t\t|| 'minifyIdentifiers' in options\n\t\t\t\t|| 'minifySyntax' in options\n\t\t\t)\n\t\t) {\n\t\t\toptions.minify = compiler.options.optimization?.minimize;\n\t\t}\n\n\t\t/**\n\t\t * Warn if `define` is used with eval-based devtools.\n\t\t * Eval devtools wrap module code in eval() strings, which prevents\n\t\t * esbuild's define from replacing identifiers (they become string content).\n\t\t */\n\t\tconst { devtool } = compiler.options;\n\t\tconst isEvalDevtool = (\n\t\t\ttypeof devtool === 'string'\n\t\t\t&& devtool.includes('eval')\n\t\t);\n\t\tlet hasWarnedEvalDefine = false;\n\n\t\tcompiler.hooks.compilation.tap(pluginName, (compilation) => {\n\t\t\tif (\n\t\t\t\t!hasWarnedEvalDefine\n\t\t\t\t&& options.define\n\t\t\t\t&& Object.keys(options.define).length > 0\n\t\t\t\t&& isEvalDevtool\n\t\t\t) {\n\t\t\t\thasWarnedEvalDefine = true;\n\t\t\t\tconst warning = new Error(\n\t\t\t\t\t`[${pluginName}] The \"define\" option may not work as expected with eval-based devtools (current: \"${devtool}\"). `\n\t\t\t\t\t+ 'Eval devtools wrap module code in eval() strings, preventing identifier replacement. '\n\t\t\t\t\t+ 'Consider using the loader\\'s \"define\" option instead, or switch to a non-eval devtool like \"source-map\".',\n\t\t\t\t);\n\t\t\t\tcompilation.warnings.push(warning as webpack5.WebpackError);\n\t\t\t}\n\t\t\tconst meta = JSON.stringify({\n\t\t\t\tname: 'esbuild-loader',\n\t\t\t\tversion,\n\t\t\t\toptions,\n\t\t\t});\n\n\t\t\tcompilation.hooks.chunkHash.tap(\n\t\t\t\tpluginName,\n\t\t\t\t(_, hash) => hash.update(meta),\n\t\t\t);\n\n\t\t\t/**\n\t\t\t * Check if sourcemaps are enabled\n\t\t\t * Webpack 4: https://github.com/webpack/webpack/blob/v4.46.0/lib/SourceMapDevToolModuleOptionsPlugin.js#L20\n\t\t\t * Webpack 5: https://github.com/webpack/webpack/blob/v5.75.0/lib/SourceMapDevToolModuleOptionsPlugin.js#LL27\n\t\t\t */\n\t\t\tlet useSourceMap = false;\n\n\t\t\t/**\n\t\t\t * `finishModules` hook is called after all the `buildModule` hooks are called,\n\t\t\t * which is where the `useSourceMap` flag is set\n\t\t\t * https://webpack.js.org/api/compilation-hooks/#finishmodules\n\t\t\t */\n\t\t\tcompilation.hooks.finishModules.tap(\n\t\t\t\tpluginName,\n\t\t\t\t(modules) => {\n\t\t\t\t\tconst firstModule = (\n\t\t\t\t\t\tArray.isArray(modules)\n\t\t\t\t\t\t\t? modules[0]\n\t\t\t\t\t\t\t: (modules as Set<webpack5.Module>).values().next().value as webpack5.Module\n\t\t\t\t\t);\n\t\t\t\t\tif (firstModule) {\n\t\t\t\t\t\tuseSourceMap = firstModule.useSourceMap;\n\t\t\t\t\t}\n\t\t\t\t},\n\t\t\t);\n\n\t\t\t// Webpack 5\n\t\t\tif ('processAssets' in compilation.hooks) {\n\t\t\t\tcompilation.hooks.processAssets.tapPromise(\n\t\t\t\t\t{\n\t\t\t\t\t\tname: pluginName,\n\t\t\t\t\t\t// @ts-expect-error undefined on Function type\n\t\t\t\t\t\tstage: compilation.constructor.PROCESS_ASSETS_STAGE_OPTIMIZE_SIZE,\n\t\t\t\t\t\tadditionalAssets: true,\n\t\t\t\t\t},\n\t\t\t\t\t() => transformAssets(options, transform, compilation, useSourceMap),\n\t\t\t\t);\n\n\t\t\t\tcompilation.hooks.statsPrinter.tap(pluginName, (statsPrinter) => {\n\t\t\t\t\tstatsPrinter.hooks.print\n\t\t\t\t\t\t.for('asset.info.minimized')\n\t\t\t\t\t\t.tap(\n\t\t\t\t\t\t\tpluginName,\n\t\t\t\t\t\t\t(\n\t\t\t\t\t\t\t\tminimized,\n\t\t\t\t\t\t\t\t{ green, formatFlag },\n\t\t\t\t\t\t\t// @ts-expect-error type incorrectly doesn't accept undefined\n\t\t\t\t\t\t\t) => (\n\t\t\t\t\t\t\t\tminimized\n\t\t\t\t\t\t\t\t\t// @ts-expect-error type incorrectly doesn't accept undefined\n\t\t\t\t\t\t\t\t\t? green(formatFlag('minimized'))\n\t\t\t\t\t\t\t\t\t: undefined\n\t\t\t\t\t\t\t),\n\t\t\t\t\t\t);\n\t\t\t\t});\n\t\t\t} else {\n\t\t\t\tcompilation.hooks.optimizeChunkAssets.tapPromise(\n\t\t\t\t\tpluginName,\n\t\t\t\t\t() => transformAssets(options, transform, compilation, useSourceMap),\n\t\t\t\t);\n\t\t\t}\n\t\t});\n\t}\n}\n"
  },
  {
    "path": "src/types.ts",
    "content": "import type { transform, TransformOptions } from 'esbuild';\n\ntype Filter = string | RegExp;\n\ntype Implementation = {\n\ttransform: typeof transform;\n};\n\ntype Except<ObjectType, Properties> = {\n\t[Key in keyof ObjectType as (Key extends Properties ? never : Key)]: ObjectType[Key];\n};\n\nexport type LoaderOptions = Except<TransformOptions, 'sourcemap' | 'sourcefile'> & {\n\n\t/** Pass a custom esbuild implementation */\n\timplementation?: Implementation;\n\n\t/**\n\t * Path to tsconfig.json file\n\t */\n\ttsconfig?: string;\n};\n\nexport type EsbuildPluginOptions = Except<TransformOptions, 'sourcemap' | 'sourcefile'> & {\n\tinclude?: Filter | Filter[];\n\texclude?: Filter | Filter[];\n\tcss?: boolean;\n\n\t/** Pass a custom esbuild implementation */\n\timplementation?: Implementation;\n};\n"
  },
  {
    "path": "tests/fixtures.ts",
    "content": "export const exportFile = (\n\tname: string,\n\tcode: string,\n) => ({\n\t'/src/index.js': `export { default } from \"./${name}\"`,\n\t[`/src/${name}`]: code,\n});\n\nconst trySyntax = (\n\tname: string,\n\tcode: string,\n) => `\n(() => {\n\ttry {\n\t\t${code}\n\t\treturn ${JSON.stringify(name)};\n\t} catch (error) {\n\t\treturn error;\n\t}\n})()\n`;\n\nexport const js = exportFile(\n\t'js.js',\n\t`export default [${[\n\t\ttrySyntax(\n\t\t\t'es2016 - Exponentiation operator',\n\t\t\t'10 ** 4',\n\t\t),\n\n\t\ttrySyntax(\n\t\t\t'es2017 - Async functions',\n\t\t\t'typeof (async () => {})',\n\t\t),\n\n\t\t// trySyntax(\n\t\t// \t'es2018 - Asynchronous iteration',\n\t\t// \t'for await (let x of []) {}',\n\t\t// ),\n\n\t\ttrySyntax(\n\t\t\t'es2018 - Spread properties',\n\t\t\t'let x = {...Object}',\n\t\t),\n\n\t\ttrySyntax(\n\t\t\t'es2018 - Rest properties',\n\t\t\t'let {...x} = Object',\n\t\t),\n\n\t\ttrySyntax(\n\t\t\t'es2019 - Optional catch binding',\n\t\t\t'try {} catch {}',\n\t\t),\n\n\t\ttrySyntax(\n\t\t\t'es2020 - Optional chaining',\n\t\t\t'Object?.keys',\n\t\t),\n\n\t\ttrySyntax(\n\t\t\t'es2020 - Nullish coalescing',\n\t\t\t'Object ?? true',\n\t\t),\n\n\t\ttrySyntax(\n\t\t\t'es2020 - import.meta',\n\t\t\t'import.meta',\n\t\t),\n\n\t\ttrySyntax(\n\t\t\t'es2021 - Logical assignment operators',\n\t\t\t'let a = false; a ??= true; a ||= true; a &&= true;',\n\t\t),\n\n\t\ttrySyntax(\n\t\t\t'es2022 - Class instance fields',\n\t\t\t'(class { x })',\n\t\t),\n\n\t\ttrySyntax(\n\t\t\t'es2022 - Static class fields',\n\t\t\t'(class { static x })',\n\t\t),\n\n\t\ttrySyntax(\n\t\t\t'es2022 - Private instance methods',\n\t\t\t'(class { #x() {} })',\n\t\t),\n\n\t\ttrySyntax(\n\t\t\t'es2022 - Private instance fields',\n\t\t\t'(class { #x })',\n\t\t),\n\n\t\ttrySyntax(\n\t\t\t'es2022 - Private static methods',\n\t\t\t'(class { static #x() {} })',\n\t\t),\n\n\t\ttrySyntax(\n\t\t\t'es2022 - Private static fields',\n\t\t\t'(class { static #x })',\n\t\t),\n\n\t\t// trySyntax(\n\t\t// \t'es2022 - Ergonomic brand checks',\n\t\t// \t'(class { #brand; static isC(obj) { return try obj.#brand; } })',\n\t\t// ),\n\n\t\ttrySyntax(\n\t\t\t'es2022 - Class static blocks',\n\t\t\t'(class { static {} })',\n\t\t),\n\n\t\t// trySyntax(\n\t\t// \t'esnext - Import assertions',\n\t\t// \t'import \"x\" assert {}',\n\t\t// ),\n\n\t].join(',')}];`,\n);\n\nexport const ts = exportFile(\n\t'ts.ts',\n\t`\n\timport type {Type} from 'foo'\n\n\tinterface Foo {}\n\n\ttype Foo = number\n\n\tdeclare module 'foo' {}\n\n\tenum BasicEnum {\n\t\tLeft,\n\t\tRight,\n\t}\n\n\tenum NamedEnum {\n\t\tSomeEnum = 'some-value',\n\t}\n\n\texport const a = BasicEnum.Left;\n\n\texport const b = NamedEnum.SomeEnum;\n\n\texport default function foo(): string {\n\t\treturn 'foo'\n\t}\n\n\t// For \"ts as tsx\" test\n\tconst bar = <T>(value: T) => fn<T>();\n\t`,\n);\n\nexport const blank = {\n\t'/src/index.js': '',\n};\n\nexport const minification = {\n\t'/src/index.js': 'export default ( stringVal )  =>  { return stringVal }',\n};\n\nexport const define = {\n\t'/src/index.js': 'export default () => [__TEST1__, __TEST2__]',\n};\n\nexport const getHelpers = {\n\t'/src/index.js': 'export default async () => {}',\n};\n\nexport const legalComments = {\n\t'/src/index.js': `\n\t\t//! legal comment\n\t\tglobalCall();\n\t`,\n};\n\nexport const css = {\n\t'/src/index.js': 'import \"./styles.css\"',\n\t'/src/styles.css': `\n\tdiv {\n\t\tcolor: red;\n\t}\n\tspan {\n\t\tmargin: 0px 10px;\n\t}\n\t`,\n};\n"
  },
  {
    "path": "tests/index.ts",
    "content": "import { describe } from 'manten';\nimport webpack4 from 'webpack';\nimport webpack5 from 'webpack5';\nimport { loader } from './specs/loader.js';\nimport { plugin } from './specs/plugin.js';\n\nconst webpacks = [\n\twebpack4,\n\twebpack5,\n];\n\ndescribe('esbuild-loader', async () => {\n\tfor (const webpack of webpacks) {\n\t\tdescribe(`Webpack ${webpack.version![0]}`, () => {\n\t\t\tloader(webpack);\n\t\t\tplugin(webpack);\n\t\t});\n\t}\n\n\tawait import('./specs/tsconfig.js');\n\tawait import('./specs/webpack5.js');\n});\n"
  },
  {
    "path": "tests/specs/loader.ts",
    "content": "import { describe, test, expect } from 'manten';\nimport { build } from 'webpack-test-utils';\nimport type webpack4 from 'webpack';\nimport type webpack5 from 'webpack5';\nimport {\n\ttype Webpack,\n\tconfigureEsbuildLoader,\n\tconfigureCssLoader,\n} from '../utils.js';\nimport * as fixtures from '../fixtures.js';\nimport type { EsbuildPluginOptions } from '#esbuild-loader';\n\nconst { exportFile } = fixtures;\n\nexport const loader = (webpack: typeof webpack4 | typeof webpack5) => {\n\tdescribe('Loader', () => {\n\t\tdescribe('Error handling', () => {\n\t\t\ttest('tsx fails to be parsed as ts', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\texportFile(\n\t\t\t\t\t\t'tsx.tsx',\n\t\t\t\t\t\t'export default <div>hello world</div>',\n\t\t\t\t\t),\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildLoader(config, {\n\t\t\t\t\t\t\ttest: /\\.tsx$/,\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\tloader: 'ts',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasErrors()).toBe(true);\n\t\t\t\tconst [error] = built.stats.compilation.errors;\n\t\t\t\texpect(error.message).toMatch('Transform failed with 1 error');\n\t\t\t});\n\t\t});\n\n\t\ttest('transforms syntax', async () => {\n\t\t\tconst built = await build(\n\t\t\t\tfixtures.js,\n\t\t\t\tconfigureEsbuildLoader,\n\t\t\t\twebpack,\n\t\t\t);\n\n\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\t\t\texpect(built.require('/dist')).toStrictEqual([\n\t\t\t\t'es2016 - Exponentiation operator',\n\t\t\t\t'es2017 - Async functions',\n\t\t\t\t'es2018 - Spread properties',\n\t\t\t\t'es2018 - Rest properties',\n\t\t\t\t'es2019 - Optional catch binding',\n\t\t\t\t'es2020 - Optional chaining',\n\t\t\t\t'es2020 - Nullish coalescing',\n\t\t\t\t'es2020 - import.meta',\n\t\t\t\t'es2021 - Logical assignment operators',\n\t\t\t\t'es2022 - Class instance fields',\n\t\t\t\t'es2022 - Static class fields',\n\t\t\t\t'es2022 - Private instance methods',\n\t\t\t\t'es2022 - Private instance fields',\n\t\t\t\t'es2022 - Private static methods',\n\t\t\t\t'es2022 - Private static fields',\n\t\t\t\t'es2022 - Class static blocks',\n\t\t\t]);\n\t\t});\n\n\t\ttest('transforms TypeScript', async () => {\n\t\t\tconst built = await build(\n\t\t\t\tfixtures.ts,\n\t\t\t\t(config) => {\n\t\t\t\t\tconfigureEsbuildLoader(config, {\n\t\t\t\t\t\ttest: /\\.ts$/,\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\twebpack,\n\t\t\t);\n\n\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\texpect(built.require('/dist')()).toBe('foo');\n\t\t});\n\n\t\ttest('transforms TSX', async () => {\n\t\t\tconst built = await build(\n\t\t\t\texportFile(\n\t\t\t\t\t'tsx.tsx',\n\t\t\t\t\t'export default (<><div>hello world</div></>)',\n\t\t\t\t),\n\t\t\t\t(config) => {\n\t\t\t\t\tconfigureEsbuildLoader(config, {\n\t\t\t\t\t\ttest: /\\.tsx$/,\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tjsxFactory: 'Array',\n\t\t\t\t\t\t\tjsxFragment: '\"Fragment\"',\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\twebpack,\n\t\t\t);\n\n\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\texpect(built.require('/dist')).toStrictEqual([\n\t\t\t\t'Fragment',\n\t\t\t\tnull,\n\t\t\t\t[\n\t\t\t\t\t'div',\n\t\t\t\t\tnull,\n\t\t\t\t\t'hello world',\n\t\t\t\t],\n\t\t\t]);\n\t\t});\n\n\t\ttest('tsconfig', async () => {\n\t\t\tconst built = await build(\n\t\t\t\texportFile(\n\t\t\t\t\t'tsx.tsx',\n\t\t\t\t\t'export default (<div>hello world</div>)',\n\t\t\t\t),\n\t\t\t\t(config) => {\n\t\t\t\t\tconfigureEsbuildLoader(config, {\n\t\t\t\t\t\ttest: /\\.tsx$/,\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\ttsconfigRaw: {\n\t\t\t\t\t\t\t\tcompilerOptions: {\n\t\t\t\t\t\t\t\t\tjsxFactory: 'Array',\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\twebpack,\n\t\t\t);\n\n\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\t\t\texpect(built.require('/dist/index.js')).toStrictEqual(['div', null, 'hello world']);\n\t\t});\n\n\t\tdescribe('implementation', () => {\n\t\t\ttest('error', async () => {\n\t\t\t\tconst runWithImplementation = async (\n\t\t\t\t\timplementation: EsbuildPluginOptions['implementation'],\n\t\t\t\t) => {\n\t\t\t\t\tconst built = await build(\n\t\t\t\t\t\tfixtures.blank,\n\t\t\t\t\t\t(config) => {\n\t\t\t\t\t\t\tconfigureEsbuildLoader(config, {\n\t\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\t\timplementation,\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t\twebpack,\n\t\t\t\t\t);\n\n\t\t\t\t\texpect(built.stats.hasErrors()).toBe(true);\n\t\t\t\t\tconst [error] = built.stats.compilation.errors;\n\t\t\t\t\tthrow error;\n\t\t\t\t};\n\n\t\t\t\t// @ts-expect-error testing invalid type\n\t\t\t\tawait expect(runWithImplementation({})).rejects.toThrow(\n\t\t\t\t\t'esbuild-loader: options.implementation.transform must be an ESBuild transform function. Received undefined',\n\t\t\t\t);\n\n\t\t\t\t// @ts-expect-error testing invalid type\n\t\t\t\tawait expect(runWithImplementation({ transform: 123 })).rejects.toThrow(\n\t\t\t\t\t'esbuild-loader: options.implementation.transform must be an ESBuild transform function. Received number',\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('custom transform function', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\tfixtures.blank,\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildLoader(config, {\n\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\timplementation: {\n\t\t\t\t\t\t\t\t\ttransform: async () => ({\n\t\t\t\t\t\t\t\t\t\tcode: 'export default \"CUSTOM_ESBUILD_IMPLEMENTATION\"',\n\t\t\t\t\t\t\t\t\t\tmap: '',\n\t\t\t\t\t\t\t\t\t\twarnings: [],\n\t\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst dist = built.fs.readFileSync('/dist/index.js', 'utf8');\n\t\t\t\texpect(dist).toContain('CUSTOM_ESBUILD_IMPLEMENTATION');\n\t\t\t});\n\t\t});\n\n\t\tdescribe('ambigious ts/tsx', () => {\n\t\t\ttest('ts via tsx', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\tfixtures.ts,\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildLoader(config, {\n\t\t\t\t\t\t\ttest: /\\.tsx?$/,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\texpect(built.require('/dist')()).toBe('foo');\n\t\t\t});\n\n\t\t\ttest('ts via tsx 2', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\texportFile(\n\t\t\t\t\t\t'ts.ts', `\n\t\t\t\t\t\texport default <V>(\n\t\t\t\t\t\t\tl: obj,\n\t\t\t\t\t\t\toptions: { [key in obj]: V },\n\t\t\t\t\t\t): V => {\n\t\t\t\t\t\t\treturn options[l];\n\t\t\t\t\t\t};\n\t\t\t\t\t`,\n\t\t\t\t\t),\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildLoader(config, {\n\t\t\t\t\t\t\ttest: /\\.tsx?$/,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\texpect(built.require('/dist')('a', { a: 1 })).toBe(1);\n\t\t\t});\n\n\t\t\ttest('ambiguous ts', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\texportFile(\n\t\t\t\t\t\t'ts.ts',\n\t\t\t\t\t\t'export default () => <a>1</a>/g',\n\t\t\t\t\t),\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildLoader(config, {\n\t\t\t\t\t\t\ttest: /\\.tsx?$/,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst dist = built.fs.readFileSync('/dist/index.js', 'utf8');\n\t\t\t\texpect(dist).toContain('(() => 1 < /a>/g)');\n\t\t\t});\n\n\t\t\ttest('ambiguous tsx', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\texportFile(\n\t\t\t\t\t\t'tsx.tsx',\n\t\t\t\t\t\t'export default () => <a>1</a>/g',\n\t\t\t\t\t),\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildLoader(config, {\n\t\t\t\t\t\t\ttest: /\\.tsx?$/,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst dist = built.fs.readFileSync('/dist/index.js', 'utf8');\n\t\t\t\texpect(dist).toContain('React.createElement');\n\t\t\t});\n\t\t});\n\n\t\tdescribe('Source-map', () => {\n\t\t\ttest('source-map eval', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\tfixtures.js,\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildLoader(config);\n\t\t\t\t\t\tconfig.devtool = 'eval-source-map';\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst dist = built.fs.readFileSync('/dist/index.js', 'utf8');\n\t\t\t\texpect(dist).toContain('eval(');\n\t\t\t});\n\n\t\t\ttest('source-map inline', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\tfixtures.js,\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildLoader(config);\n\t\t\t\t\t\tconfig.devtool = 'inline-source-map';\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst dist = built.fs.readFileSync('/dist/index.js', 'utf8');\n\t\t\t\texpect(dist).toContain('sourceMappingURL');\n\t\t\t});\n\n\t\t\ttest('source-map file', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\tfixtures.js,\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildLoader(config);\n\t\t\t\t\t\tconfig.devtool = 'source-map';\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst { assets } = built.stats.compilation;\n\t\t\t\texpect(assets).toHaveProperty(['index.js']);\n\t\t\t\texpect(assets).toHaveProperty(['index.js.map']);\n\t\t\t});\n\n\t\t\ttest('source-map plugin', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\tfixtures.js,\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildLoader(config);\n\n\t\t\t\t\t\tdelete config.devtool;\n\t\t\t\t\t\tconfig.plugins!.push(\n\t\t\t\t\t\t\tnew webpack.SourceMapDevToolPlugin({}) as Webpack['SourceMapDevToolPlugin'],\n\t\t\t\t\t\t);\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst dist = built.fs.readFileSync('/dist/index.js', 'utf8');\n\t\t\t\texpect(dist).toContain('sourceMappingURL');\n\t\t\t});\n\t\t});\n\n\t\ttest('webpack magic comments', async () => {\n\t\t\tconst built = await build({\n\t\t\t\t'/src/index.js': `\n\t\t\t\t\tconst chunkA = import(/* webpackChunkName: \"named-chunk-foo\" */'./chunk-a.js')\n\t\t\t\t\tconst chunkB = import(/* webpackChunkName: \"named-chunk-bar\" */'./chunk-b.js')\n\t\t\t\t\texport default async () => (await chunkA).default + (await chunkB).default;\n\t\t\t\t`,\n\t\t\t\t'/src/chunk-a.js': 'export default 1',\n\t\t\t\t'/src/chunk-b.js': 'export default 2',\n\t\t\t}, configureEsbuildLoader, webpack);\n\n\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\tconst { assets } = built.stats.compilation;\n\t\t\texpect(assets).toHaveProperty(['index.js']);\n\t\t\texpect(assets).toHaveProperty(['named-chunk-foo.js']);\n\t\t\texpect(assets).toHaveProperty(['named-chunk-bar.js']);\n\t\t\texpect(await built.require('/dist')()).toBe(3);\n\t\t});\n\n\t\ttest('CSS minification', async () => {\n\t\t\tconst built = await build(\n\t\t\t\tfixtures.css,\n\t\t\t\t(config) => {\n\t\t\t\t\tconfigureEsbuildLoader(config);\n\t\t\t\t\tconst cssRule = configureCssLoader(config);\n\t\t\t\t\tcssRule.use.push({\n\t\t\t\t\t\tloader: 'esbuild-loader',\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tminify: true,\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\twebpack,\n\t\t\t);\n\n\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\tconst code = built.fs.readFileSync('/dist/index.js', 'utf8');\n\t\t\texpect(code).toContain('div{color:red}');\n\t\t});\n\n\t\ttest('Keeps dynamic imports by default', async () => {\n\t\t\tconst built = await build(\n\t\t\t\t{\n\t\t\t\t\t'/src/index.js': 'export default async () => (await import(\"./test2.js\")).default',\n\t\t\t\t\t'/src/test2.js': 'export default \"test2\"',\n\t\t\t\t},\n\t\t\t\t(config) => {\n\t\t\t\t\tconfigureEsbuildLoader(config, { options: { target: 'chrome52' } });\n\t\t\t\t},\n\t\t\t\twebpack,\n\t\t\t);\n\n\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\tconst { assets } = built.stats.compilation;\n\t\t\texpect(assets).toHaveProperty(['index.js']);\n\n\t\t\t// Chunk split because esbuild preserved the dynamic import\n\t\t\texpect(Object.keys(assets).length).toBe(2);\n\t\t\texpect(await built.require('/dist')()).toBe('test2');\n\t\t});\n\n\t\ttest('Dynamic imports can be disabled', async () => {\n\t\t\tconst built = await build(\n\t\t\t\t{\n\t\t\t\t\t'/src/index.js': 'export default async () => (await import(\"./test2.js\")).default',\n\t\t\t\t\t'/src/test2.js': 'export default \"test2\"',\n\t\t\t\t},\n\t\t\t\t(config) => {\n\t\t\t\t\tconfigureEsbuildLoader(config, {\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\ttarget: 'chrome52',\n\t\t\t\t\t\t\tsupported: { 'dynamic-import': false },\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\twebpack,\n\t\t\t);\n\n\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\tconst { assets } = built.stats.compilation;\n\t\t\texpect(assets).toHaveProperty(['index.js']);\n\n\t\t\t// No chunk split because esbuild removed the dynamic import\n\t\t\texpect(Object.keys(assets).length).toBe(1);\n\t\t\texpect(await built.require('/dist')()).toBe('test2');\n\t\t});\n\n\t\ttest('define replaces identifiers', async () => {\n\t\t\tconst built = await build(\n\t\t\t\t{\n\t\t\t\t\t'/src/index.js': 'export default MY_CONSTANT',\n\t\t\t\t},\n\t\t\t\t(config) => {\n\t\t\t\t\tconfigureEsbuildLoader(config, {\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tdefine: {\n\t\t\t\t\t\t\t\tMY_CONSTANT: JSON.stringify('replaced-value'),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t\twebpack,\n\t\t\t);\n\n\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\texpect(built.require('/dist')).toBe('replaced-value');\n\t\t});\n\n\t\ttest('define works with eval devtool in loader', async () => {\n\t\t\tconst built = await build(\n\t\t\t\t{\n\t\t\t\t\t'/src/index.js': 'export default MY_CONSTANT',\n\t\t\t\t},\n\t\t\t\t(config) => {\n\t\t\t\t\tconfigureEsbuildLoader(config, {\n\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\tdefine: {\n\t\t\t\t\t\t\t\tMY_CONSTANT: JSON.stringify('works-with-eval'),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\t\t\t\t\t});\n\t\t\t\t\tconfig.devtool = 'eval-source-map';\n\t\t\t\t},\n\t\t\t\twebpack,\n\t\t\t);\n\n\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t// Loader's define works with eval devtools because it runs BEFORE bundling\n\t\t\texpect(built.require('/dist')).toBe('works-with-eval');\n\t\t});\n\t});\n};\n"
  },
  {
    "path": "tests/specs/plugin.ts",
    "content": "import { describe, test, expect } from 'manten';\nimport { build } from 'webpack-test-utils';\nimport type webpack4 from 'webpack';\nimport webpack5 from 'webpack5';\nimport * as esbuild from 'esbuild';\nimport { merge } from 'webpack-merge';\nimport {\n\ttype Webpack,\n\tisWebpack4,\n\tconfigureEsbuildMinifyPlugin,\n\tconfigureMiniCssExtractPlugin,\n} from '../utils.js';\nimport * as fixtures from '../fixtures.js';\nimport { EsbuildPlugin, type EsbuildPluginOptions } from '#esbuild-loader';\n\nconst assertMinified = (code: string) => {\n\texpect(code).not.toMatch(/\\s{2,}/);\n\texpect(code).not.toMatch('stringVal');\n\texpect(code).not.toMatch('return ');\n};\n\nconst countIife = (code: string) => Array.from(code.matchAll(/\\(\\(\\)=>\\{/g)).length;\n\nexport const plugin = (webpack: typeof webpack4 | typeof webpack5) => {\n\tconst webpackIs4 = isWebpack4(webpack);\n\n\tdescribe('Plugin', () => {\n\t\tdescribe('Minify JS', () => {\n\t\t\tdescribe('should not minify by default', () => {\n\t\t\t\ttest('minimizer', async () => {\n\t\t\t\t\tconst built = await build(\n\t\t\t\t\t\tfixtures.minification,\n\t\t\t\t\t\t(config) => {\n\t\t\t\t\t\t\tconfig.optimization = {\n\t\t\t\t\t\t\t\tminimize: false,\n\t\t\t\t\t\t\t\tminimizer: [\n\t\t\t\t\t\t\t\t\tnew EsbuildPlugin(),\n\t\t\t\t\t\t\t\t],\n\t\t\t\t\t\t\t};\n\t\t\t\t\t\t},\n\t\t\t\t\t\twebpack,\n\t\t\t\t\t);\n\n\t\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\t\tconst exportedFunction = built.require('/dist/');\n\t\t\t\t\texpect(exportedFunction('hello world')).toBe('hello world');\n\t\t\t\t\texpect(exportedFunction.toString()).toMatch(/\\s{2,}/);\n\t\t\t\t});\n\n\t\t\t\ttest('plugin', async () => {\n\t\t\t\t\tconst built = await build(\n\t\t\t\t\t\tfixtures.minification,\n\t\t\t\t\t\t(config) => {\n\t\t\t\t\t\t\tconfig.plugins?.push(new EsbuildPlugin());\n\t\t\t\t\t\t},\n\t\t\t\t\t\twebpack,\n\t\t\t\t\t);\n\n\t\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\t\tconst exportedFunction = built.require('/dist/');\n\t\t\t\t\texpect(exportedFunction('hello world')).toBe('hello world');\n\t\t\t\t\texpect(exportedFunction.toString()).toMatch(/\\s{2,}/);\n\t\t\t\t});\n\n\t\t\t\ttest('plugin with minimize enabled', async () => {\n\t\t\t\t\tconst built = await build(\n\t\t\t\t\t\tfixtures.minification,\n\t\t\t\t\t\t(config) => {\n\t\t\t\t\t\t\tconfig.optimization = {\n\t\t\t\t\t\t\t\tminimize: true,\n\n\t\t\t\t\t\t\t\t// Remove Terser\n\t\t\t\t\t\t\t\tminimizer: [],\n\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\tconfig.plugins?.push(new EsbuildPlugin());\n\t\t\t\t\t\t},\n\t\t\t\t\t\twebpack,\n\t\t\t\t\t);\n\n\t\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\t\tconst exportedFunction = built.require('/dist/');\n\t\t\t\t\texpect(exportedFunction('hello world')).toBe('hello world');\n\t\t\t\t\texpect(exportedFunction.toString()).toMatch(/\\s{2,}/);\n\t\t\t\t});\n\t\t\t});\n\n\t\t\ttest('minify', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\tfixtures.minification,\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config);\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst exportedFunction = built.require('/dist/');\n\t\t\t\texpect(exportedFunction('hello world')).toBe('hello world');\n\t\t\t\tassertMinified(exportedFunction.toString());\n\t\t\t});\n\n\t\t\ttest('minifyWhitespace', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\tfixtures.minification,\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config, {\n\t\t\t\t\t\t\tminifyWhitespace: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst exportedFunction = built.require('/dist/');\n\t\t\t\texpect(exportedFunction('hello world')).toBe('hello world');\n\n\t\t\t\tconst code = exportedFunction.toString();\n\t\t\t\texpect(code).not.toMatch(/\\s{2,}/);\n\t\t\t\texpect(code).toMatch('stringVal');\n\t\t\t\texpect(code).toMatch('return ');\n\t\t\t});\n\n\t\t\ttest('minifyIdentifiers', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\tfixtures.minification,\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config, {\n\t\t\t\t\t\t\tminifyIdentifiers: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst exportedFunction = built.require('/dist/');\n\t\t\t\texpect(exportedFunction('hello world')).toBe('hello world');\n\n\t\t\t\tconst code = exportedFunction.toString();\n\t\t\t\texpect(code).toMatch(/\\s{2,}/);\n\t\t\t\texpect(code).not.toMatch('stringVal');\n\t\t\t\texpect(code).toMatch('return ');\n\t\t\t});\n\n\t\t\ttest('minifySyntax', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\tfixtures.minification,\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config, {\n\t\t\t\t\t\t\tminifySyntax: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst exportedFunction = built.require('/dist/');\n\t\t\t\texpect(exportedFunction('hello world')).toBe('hello world');\n\n\t\t\t\tconst code = exportedFunction.toString();\n\t\t\t\texpect(code).toMatch(/\\s/);\n\t\t\t\texpect(code).toMatch('stringVal');\n\t\t\t\texpect(code).not.toMatch('return ');\n\t\t\t});\n\n\t\t\ttest('should minify when used alongside plugin', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\tfixtures.minification,\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config);\n\t\t\t\t\t\tconfig.plugins?.push(new EsbuildPlugin());\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst exportedFunction = built.require('/dist/');\n\t\t\t\texpect(exportedFunction('hello world')).toBe('hello world');\n\t\t\t\tassertMinified(exportedFunction.toString());\n\t\t\t});\n\n\t\t\ttest('minify chunks & filter using include/exclude', async () => {\n\t\t\t\tconst built = await build({\n\t\t\t\t\t'/src/index.js': `\n\t\t\t\t\t\tconst foo = import(/* webpackChunkName: \"named-chunk-foo\" */'./foo.js')\n\t\t\t\t\t\tconst bar = import(/* webpackChunkName: \"named-chunk-bar\" */'./bar.js')\n\t\t\t\t\t\tconst baz = import(/* webpackChunkName: \"named-chunk-baz\" */'./baz.js')\n\t\t\t\t\t\texport default [foo, bar, baz];\n\t\t\t\t\t`,\n\t\t\t\t\t'/src/foo.js': fixtures.minification['/src/index.js'],\n\t\t\t\t\t'/src/bar.js': fixtures.minification['/src/index.js'],\n\t\t\t\t\t'/src/baz.js': fixtures.minification['/src/index.js'],\n\t\t\t\t}, (config) => {\n\t\t\t\t\tconfigureEsbuildMinifyPlugin(config, {\n\t\t\t\t\t\tinclude: /ba./,\n\t\t\t\t\t\texclude: /baz/,\n\t\t\t\t\t});\n\t\t\t\t}, webpack);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst chunkFoo = built.fs.readFileSync('/dist/named-chunk-foo.js', 'utf8').toString();\n\n\t\t\t\t// The string \"__webpack_require__\" is only present in unminified chunks\n\t\t\t\texpect(chunkFoo).toContain('__webpack_require__');\n\n\t\t\t\tconst chunkBar = built.fs.readFileSync('/dist/named-chunk-bar.js', 'utf8').toString();\n\t\t\t\texpect(chunkBar).not.toContain('__webpack_require__');\n\t\t\t\tassertMinified(chunkBar);\n\n\t\t\t\tconst chunkBaz = built.fs.readFileSync('/dist/named-chunk-baz.js', 'utf8').toString();\n\t\t\t\texpect(chunkBaz).toContain('__webpack_require__');\n\t\t\t});\n\n\t\t\tdescribe('devtool', () => {\n\t\t\t\ttest('minify w/ no devtool', async () => {\n\t\t\t\t\tconst built = await build(\n\t\t\t\t\t\tfixtures.blank,\n\t\t\t\t\t\t(config) => {\n\t\t\t\t\t\t\tdelete config.devtool;\n\t\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config);\n\t\t\t\t\t\t},\n\t\t\t\t\t\twebpack,\n\t\t\t\t\t);\n\n\t\t\t\t\tconst { stats } = built;\n\t\t\t\t\texpect(stats.hasWarnings()).toBe(false);\n\t\t\t\t\texpect(stats.hasErrors()).toBe(false);\n\t\t\t\t\texpect(\n\t\t\t\t\t\tObject.keys(stats.compilation.assets).length,\n\t\t\t\t\t).toBe(1);\n\n\t\t\t\t\tconst file = built.fs.readFileSync('/dist/index.js', 'utf8');\n\t\t\t\t\texpect(file).not.toContain('//# sourceURL');\n\t\t\t\t});\n\n\t\t\t\ttest('minify w/ devtool inline-source-map', async () => {\n\t\t\t\t\tconst built = await build(\n\t\t\t\t\t\tfixtures.blank,\n\t\t\t\t\t\t(config) => {\n\t\t\t\t\t\t\tconfig.devtool = 'inline-source-map';\n\t\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config);\n\t\t\t\t\t\t},\n\t\t\t\t\t\twebpack,\n\t\t\t\t\t);\n\n\t\t\t\t\tconst { stats } = built;\n\t\t\t\t\texpect(stats.hasWarnings()).toBe(false);\n\t\t\t\t\texpect(stats.hasErrors()).toBe(false);\n\t\t\t\t\texpect(\n\t\t\t\t\t\tObject.keys(stats.compilation.assets).length,\n\t\t\t\t\t).toBe(1);\n\n\t\t\t\t\tconst file = built.fs.readFileSync('/dist/index.js', 'utf8');\n\t\t\t\t\texpect(file).toContain('//# sourceMappingURL=data:application/');\n\t\t\t\t});\n\n\t\t\t\ttest('minify w/ devtool source-map', async () => {\n\t\t\t\t\tconst built = await build(\n\t\t\t\t\t\tfixtures.blank,\n\t\t\t\t\t\t(config) => {\n\t\t\t\t\t\t\tconfig.devtool = 'source-map';\n\t\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config);\n\t\t\t\t\t\t},\n\t\t\t\t\t\twebpack,\n\t\t\t\t\t);\n\n\t\t\t\t\tconst { stats } = built;\n\t\t\t\t\texpect(stats.hasWarnings()).toBe(false);\n\t\t\t\t\texpect(stats.hasErrors()).toBe(false);\n\t\t\t\t\texpect(\n\t\t\t\t\t\tObject.keys(stats.compilation.assets),\n\t\t\t\t\t).toStrictEqual([\n\t\t\t\t\t\t'index.js',\n\t\t\t\t\t\t'index.js.map',\n\t\t\t\t\t]);\n\n\t\t\t\t\tconst file = built.fs.readFileSync('/dist/index.js', 'utf8');\n\t\t\t\t\texpect(file).toContain('//# sourceMappingURL=index.js.map');\n\t\t\t\t});\n\n\t\t\t\ttest('minify w/ source-map option and source-map plugin inline', async () => {\n\t\t\t\t\tconst built = await build(\n\t\t\t\t\t\tfixtures.blank,\n\t\t\t\t\t\t(config) => {\n\t\t\t\t\t\t\tdelete config.devtool;\n\t\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config);\n\n\t\t\t\t\t\t\tconfig.plugins!.push(\n\t\t\t\t\t\t\t\tnew webpack.SourceMapDevToolPlugin({}) as Webpack['SourceMapDevToolPlugin'],\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t},\n\t\t\t\t\t\twebpack,\n\t\t\t\t\t);\n\n\t\t\t\t\tconst { stats } = built;\n\t\t\t\t\texpect(stats.hasWarnings()).toBe(false);\n\t\t\t\t\texpect(stats.hasErrors()).toBe(false);\n\t\t\t\t\texpect(\n\t\t\t\t\t\tObject.keys(stats.compilation.assets).length,\n\t\t\t\t\t).toBe(1);\n\n\t\t\t\t\tconst file = built.fs.readFileSync('/dist/index.js', 'utf8');\n\t\t\t\t\texpect(file).toContain('//# sourceMappingURL=data:application/');\n\t\t\t\t});\n\n\t\t\t\ttest('minify w/ source-map option and source-map plugin external', async () => {\n\t\t\t\t\tconst built = await build(\n\t\t\t\t\t\tfixtures.blank,\n\t\t\t\t\t\t(config) => {\n\t\t\t\t\t\t\tdelete config.devtool;\n\t\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config);\n\n\t\t\t\t\t\t\tconfig.plugins!.push(\n\t\t\t\t\t\t\t\tnew webpack.SourceMapDevToolPlugin({\n\t\t\t\t\t\t\t\t\tfilename: 'index.js.map',\n\t\t\t\t\t\t\t\t}) as Webpack['SourceMapDevToolPlugin'],\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t},\n\t\t\t\t\t\twebpack,\n\t\t\t\t\t);\n\n\t\t\t\t\tconst { stats } = built;\n\t\t\t\t\texpect(stats.hasWarnings()).toBe(false);\n\t\t\t\t\texpect(stats.hasErrors()).toBe(false);\n\t\t\t\t\texpect(\n\t\t\t\t\t\tObject.keys(stats.compilation.assets),\n\t\t\t\t\t).toStrictEqual([\n\t\t\t\t\t\t'index.js',\n\t\t\t\t\t\t'index.js.map',\n\t\t\t\t\t]);\n\n\t\t\t\t\tconst file = built.fs.readFileSync('/dist/index.js', 'utf8');\n\t\t\t\t\texpect(file).toContain('//# sourceMappingURL=index.js.map');\n\t\t\t\t});\n\t\t\t});\n\n\t\t\ttest('minify w/ query strings', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\t{\n\t\t\t\t\t\t'/src/index.js': 'import(/* webpackChunkName: \"chunk\" */\"./chunk.js\")',\n\t\t\t\t\t\t'/src/chunk.js': '',\n\t\t\t\t\t},\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfig.output!.filename = '[name].js?foo=bar';\n\t\t\t\t\t\tconfig.output!.chunkFilename = '[name].js?foo=bar';\n\n\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config);\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\tconst { stats } = built;\n\t\t\t\texpect(stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(stats.hasErrors()).toBe(false);\n\t\t\t\texpect(\n\t\t\t\t\tObject.keys(stats.compilation.assets).sort(),\n\t\t\t\t).toStrictEqual([\n\t\t\t\t\t'chunk.js?foo=bar',\n\t\t\t\t\t'index.js?foo=bar',\n\t\t\t\t]);\n\n\t\t\t\t// The actual file name does not include the query string\n\t\t\t\tconst file = built.fs.readFileSync('/dist/index.js', 'utf8');\n\t\t\t\texpect(file).toMatch('?foo=bar');\n\t\t\t});\n\n\t\t\tdescribe('legalComments', () => {\n\t\t\t\ttest('minify w/ legalComments - default is inline', async () => {\n\t\t\t\t\tconst builtDefault = await build(\n\t\t\t\t\t\tfixtures.legalComments,\n\t\t\t\t\t\t(config) => {\n\t\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config);\n\t\t\t\t\t\t},\n\t\t\t\t\t\twebpack,\n\t\t\t\t\t);\n\n\t\t\t\t\tconst builtInline = await build(\n\t\t\t\t\t\tfixtures.legalComments,\n\t\t\t\t\t\t(config) => {\n\t\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config, {\n\t\t\t\t\t\t\t\tlegalComments: 'inline',\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t\twebpack,\n\t\t\t\t\t);\n\n\t\t\t\t\tconst fileInline = builtInline.fs.readFileSync('/dist/index.js', 'utf8');\n\t\t\t\t\tconst fileDefault = builtDefault.fs.readFileSync('/dist/index.js', 'utf8');\n\n\t\t\t\t\texpect(fileDefault).toMatch('//! legal comment');\n\t\t\t\t\texpect(fileDefault).toBe(fileInline);\n\t\t\t\t});\n\n\t\t\t\ttest('minify w/ legalComments - eof', async () => {\n\t\t\t\t\tconst built = await build(\n\t\t\t\t\t\tfixtures.legalComments,\n\t\t\t\t\t\t(config) => {\n\t\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config, {\n\t\t\t\t\t\t\t\tlegalComments: 'eof',\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t\twebpack,\n\t\t\t\t\t);\n\n\t\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\t\tconst file = built.fs.readFileSync('/dist/index.js').toString();\n\t\t\t\t\texpect(file.trim().endsWith('//! legal comment')).toBe(true);\n\t\t\t\t});\n\n\t\t\t\ttest('minify w/ legalComments - none', async () => {\n\t\t\t\t\tconst built = await build(\n\t\t\t\t\t\tfixtures.legalComments,\n\t\t\t\t\t\t(config) => {\n\t\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config, {\n\t\t\t\t\t\t\t\tlegalComments: 'none',\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t\twebpack,\n\t\t\t\t\t);\n\n\t\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\t\tconst file = built.fs.readFileSync('/dist/index.js', 'utf8');\n\t\t\t\t\texpect(file).not.toMatch('//! legal comment');\n\t\t\t\t});\n\n\t\t\t\ttest('minify w/ legalComments - external', async () => {\n\t\t\t\t\tconst built = await build(\n\t\t\t\t\t\tfixtures.legalComments,\n\t\t\t\t\t\t(config) => {\n\t\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config, {\n\t\t\t\t\t\t\t\tlegalComments: 'external',\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t\twebpack,\n\t\t\t\t\t);\n\n\t\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\t\texpect(Object.keys(built.stats.compilation.assets)).toStrictEqual([\n\t\t\t\t\t\t'index.js',\n\t\t\t\t\t\t'index.js.LEGAL.txt',\n\t\t\t\t\t]);\n\t\t\t\t\tconst file = built.fs.readFileSync('/dist/index.js', 'utf8');\n\t\t\t\t\texpect(file).not.toMatch('//! legal comment');\n\n\t\t\t\t\tconst extracted = built.fs.readFileSync('/dist/index.js.LEGAL.txt', 'utf8');\n\t\t\t\t\texpect(extracted).toMatch('//! legal comment');\n\t\t\t\t});\n\t\t\t});\n\t\t});\n\n\t\tdescribe('implementation', () => {\n\t\t\ttest('error', async () => {\n\t\t\t\tconst runWithImplementation = async (implementation: EsbuildPluginOptions['implementation']) => {\n\t\t\t\t\tawait build(\n\t\t\t\t\t\tfixtures.blank,\n\t\t\t\t\t\t(config) => {\n\t\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config, {\n\t\t\t\t\t\t\t\timplementation,\n\t\t\t\t\t\t\t});\n\t\t\t\t\t\t},\n\t\t\t\t\t\twebpack,\n\t\t\t\t\t);\n\t\t\t\t};\n\n\t\t\t\tawait expect(\n\t\t\t\t\t// @ts-expect-error testing invalid type\n\t\t\t\t\trunWithImplementation({}),\n\t\t\t\t).rejects.toThrow(\n\t\t\t\t\t'[EsbuildPlugin] implementation.transform must be an esbuild transform function. Received undefined',\n\t\t\t\t);\n\n\t\t\t\tawait expect(\n\t\t\t\t\t// @ts-expect-error testing invalid type\n\t\t\t\t\trunWithImplementation({ transform: 123 }),\n\t\t\t\t).rejects.toThrow(\n\t\t\t\t\t'[EsbuildPlugin] implementation.transform must be an esbuild transform function. Received number',\n\t\t\t\t);\n\t\t\t});\n\n\t\t\ttest('customizable', async () => {\n\t\t\t\tconst code = 'export function foo() { return \"CUSTOM_ESBUILD_IMPLEMENTATION\"; }';\n\t\t\t\tconst built = await build(\n\t\t\t\t\tfixtures.blank,\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config, {\n\t\t\t\t\t\t\timplementation: {\n\t\t\t\t\t\t\t\ttransform: async () => ({\n\t\t\t\t\t\t\t\t\tcode,\n\t\t\t\t\t\t\t\t\tmap: '',\n\t\t\t\t\t\t\t\t\twarnings: [],\n\t\t\t\t\t\t\t\t\tmangleCache: {},\n\t\t\t\t\t\t\t\t\tlegalComments: '',\n\t\t\t\t\t\t\t\t}),\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\t\t\t\texpect(\n\t\t\t\t\tbuilt.fs.readFileSync('/dist/index.js', 'utf8'),\n\t\t\t\t).toBe(code);\n\t\t\t});\n\n\t\t\ttest('customize with real esbuild', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\tfixtures.minification,\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config, {\n\t\t\t\t\t\t\timplementation: esbuild,\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst exportedFunction = built.require('/dist/');\n\t\t\t\texpect(exportedFunction('hello world')).toBe('hello world');\n\t\t\t\tassertMinified(exportedFunction.toString());\n\t\t\t});\n\t\t});\n\n\t\tdescribe('CSS', () => {\n\t\t\ttest('minify CSS asset', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\tfixtures.css,\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config, {\n\t\t\t\t\t\t\tcss: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconfigureMiniCssExtractPlugin(config);\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst file = built.fs.readFileSync('/dist/index.css').toString();\n\t\t\t\texpect(file.trim()).not.toMatch(/\\s{2,}/);\n\t\t\t});\n\n\t\t\ttest('exclude', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\tfixtures.css,\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config, {\n\t\t\t\t\t\t\tcss: true,\n\t\t\t\t\t\t\texclude: /index\\.css$/,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconfigureMiniCssExtractPlugin(config);\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst file = built.fs.readFileSync('/dist/index.css').toString();\n\t\t\t\texpect(file.trim()).toMatch(/\\s{2,}/);\n\t\t\t});\n\n\t\t\ttest('minify w/ source-map', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\tfixtures.css,\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfig.devtool = 'source-map';\n\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config, {\n\t\t\t\t\t\t\tcss: true,\n\t\t\t\t\t\t});\n\t\t\t\t\t\tconfigureMiniCssExtractPlugin(config);\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst cssFile = built.fs.readFileSync('/dist/index.css').toString();\n\t\t\t\tconst css = cssFile.trim().split('\\n');\n\t\t\t\texpect(css[0]).not.toMatch(/\\s{2,}/);\n\t\t\t\texpect(css[2]).toMatch(/sourceMappingURL/);\n\n\t\t\t\tconst sourcemapFile = built.fs.readFileSync('/dist/index.css.map', 'utf8');\n\t\t\t\texpect(sourcemapFile).toMatch(/styles\\.css/);\n\t\t\t});\n\t\t});\n\n\t\ttest('supports Source without #sourceAndMap()', async () => {\n\t\t\tconst createSource = (content: string) => ({\n\t\t\t\tsource: () => content,\n\t\t\t\tsize: () => Buffer.byteLength(content),\n\t\t\t}) as webpack5.sources.Source;\n\n\t\t\tconst built = await build(fixtures.blank, (config) => {\n\t\t\t\tconfigureEsbuildMinifyPlugin(config);\n\n\t\t\t\tconfig.plugins!.push({\n\t\t\t\t\tapply: (compiler) => {\n\t\t\t\t\t\tcompiler.hooks.compilation.tap('test', (compilation) => {\n\t\t\t\t\t\t\tcompilation.hooks.processAssets.tap(\n\t\t\t\t\t\t\t\t{ name: 'test' },\n\t\t\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\t\t\tcompilation.emitAsset(\n\t\t\t\t\t\t\t\t\t\t'test.js',\n\t\t\t\t\t\t\t\t\t\tcreateSource('console.log( 1  +  1)'),\n\t\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t});\n\t\t\t\t\t},\n\t\t\t\t});\n\t\t\t}, webpack5);\n\n\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\texpect(Object.keys(built.stats.compilation.assets)).toStrictEqual([\n\t\t\t\t'index.js',\n\t\t\t\t'test.js',\n\t\t\t]);\n\t\t\texpect(\n\t\t\t\tbuilt.fs.readFileSync('/dist/test.js', 'utf8'),\n\t\t\t).toBe('console.log(2);\\n');\n\t\t});\n\n\t\tdescribe('minify targets', () => {\n\t\t\ttest('no iife for node', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\tfixtures.getHelpers,\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config, {\n\t\t\t\t\t\t\ttarget: 'es2015',\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tconfig.target = webpackIs4 ? 'node' : ['node'];\n\t\t\t\t\t\tdelete config.output?.libraryTarget;\n\t\t\t\t\t\tdelete config.output?.libraryExport;\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst code = built.fs.readFileSync('/dist/index.js', 'utf8').toString();\n\t\t\t\texpect(code.startsWith('var ')).toBe(true);\n\t\t\t});\n\n\t\t\ttest('no iife for web with high target (no helpers are added)', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\tfixtures.getHelpers,\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config);\n\n\t\t\t\t\t\tconfig.target = webpackIs4 ? 'web' : ['web'];\n\t\t\t\t\t\tdelete config.output?.libraryTarget;\n\t\t\t\t\t\tdelete config.output?.libraryExport;\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst code = built.fs.readFileSync('/dist/index.js', 'utf8').toString();\n\t\t\t\texpect(code.startsWith('(()=>{var ')).toBe(false);\n\t\t\t\texpect(countIife(code)).toBe(webpackIs4 ? 0 : 1);\n\t\t\t});\n\n\t\t\ttest('iife for web & low target', async () => {\n\t\t\t\tconst built = await build(\n\t\t\t\t\tfixtures.getHelpers,\n\t\t\t\t\t(config) => {\n\t\t\t\t\t\tconfigureEsbuildMinifyPlugin(config, {\n\t\t\t\t\t\t\ttarget: 'es2015',\n\t\t\t\t\t\t});\n\n\t\t\t\t\t\tconfig.target = webpackIs4 ? 'web' : ['web'];\n\t\t\t\t\t\tdelete config.output?.libraryTarget;\n\t\t\t\t\t\tdelete config.output?.libraryExport;\n\t\t\t\t\t},\n\t\t\t\t\twebpack,\n\t\t\t\t);\n\n\t\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\t\tconst code = built.fs.readFileSync('/dist/index.js', 'utf8').toString();\n\t\t\t\texpect(code.startsWith('(()=>{var ')).toBe(true);\n\t\t\t\texpect(code.endsWith('})();\\n')).toBe(true);\n\t\t\t\texpect(countIife(code)).toBe(webpackIs4 ? 1 : 2);\n\t\t\t});\n\t\t});\n\n\t\ttest('supports webpack-merge', async () => {\n\t\t\tconst built = await build(\n\t\t\t\tfixtures.minification,\n\t\t\t\t(config) => {\n\t\t\t\t\tconfigureEsbuildMinifyPlugin(config);\n\t\t\t\t\tconst clonedConfig = merge({}, config);\n\t\t\t\t\tconfig.optimization = clonedConfig.optimization;\n\t\t\t\t},\n\t\t\t\twebpack,\n\t\t\t);\n\n\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\tconst exportedFunction = built.require('/dist/');\n\t\t\texpect(exportedFunction('hello world')).toBe('hello world');\n\t\t\tassertMinified(exportedFunction.toString());\n\t\t});\n\n\t\t// https://github.com/privatenumber/esbuild-loader/issues/356\n\t\ttest('can handle empty modules set', async () => {\n\t\t\tawait expect(build(\n\t\t\t\tfixtures.blank,\n\t\t\t\t(config) => {\n\t\t\t\t\tconfig.entry = 'not-there.js';\n\t\t\t\t\tconfigureEsbuildMinifyPlugin(config);\n\t\t\t\t},\n\t\t\t\twebpack,\n\t\t\t)).resolves.toBeTruthy();\n\t\t});\n\n\t\ttest('multiple plugins', async () => {\n\t\t\tconst built = await build(\n\t\t\t\tfixtures.define,\n\t\t\t\t(config) => {\n\t\t\t\t\tconfigureEsbuildMinifyPlugin(config);\n\t\t\t\t\tconfig.plugins?.push(\n\t\t\t\t\t\tnew EsbuildPlugin({\n\t\t\t\t\t\t\tdefine: {\n\t\t\t\t\t\t\t\t__TEST1__: '123',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t\tnew EsbuildPlugin({\n\t\t\t\t\t\t\tdefine: {\n\t\t\t\t\t\t\t\t__TEST2__: '321',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\twebpack,\n\t\t\t);\n\n\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\t\tconst exportedFunction = built.require('/dist/');\n\t\t\texpect(exportedFunction('hello world')).toStrictEqual([123, 321]);\n\t\t});\n\n\t\ttest('warns when define is used with eval devtool', async () => {\n\t\t\tconst built = await build(\n\t\t\t\tfixtures.minification,\n\t\t\t\t(config) => {\n\t\t\t\t\tconfig.devtool = 'eval-source-map';\n\t\t\t\t\tconfig.plugins?.push(\n\t\t\t\t\t\tnew EsbuildPlugin({\n\t\t\t\t\t\t\tdefine: {\n\t\t\t\t\t\t\t\t__TEST__: '\"value\"',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\twebpack,\n\t\t\t);\n\n\t\t\texpect(built.stats.hasWarnings()).toBe(true);\n\t\t\tconst warnings = built.stats.toJson().warnings!;\n\t\t\texpect(warnings.length).toBe(1);\n\t\t\t// Webpack 4 returns string, Webpack 5 returns object with message property\n\t\t\tconst warningMessage = typeof warnings[0] === 'string' ? warnings[0] : warnings[0].message;\n\t\t\texpect(warningMessage).toMatch('[EsbuildPlugin] The \"define\" option may not work as expected with eval-based devtools (current: \"eval-source-map\")');\n\t\t\texpect(warningMessage).toMatch('Consider using the loader\\'s \"define\" option instead');\n\t\t});\n\n\t\ttest('no warning when define is used with non-eval devtool', async () => {\n\t\t\tconst built = await build(\n\t\t\t\tfixtures.minification,\n\t\t\t\t(config) => {\n\t\t\t\t\tconfig.devtool = 'source-map';\n\t\t\t\t\tconfig.plugins?.push(\n\t\t\t\t\t\tnew EsbuildPlugin({\n\t\t\t\t\t\t\tdefine: {\n\t\t\t\t\t\t\t\t__TEST__: '\"value\"',\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\twebpack,\n\t\t\t);\n\n\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\t\t});\n\n\t\ttest('no warning when define is not used with eval devtool', async () => {\n\t\t\tconst built = await build(\n\t\t\t\tfixtures.minification,\n\t\t\t\t(config) => {\n\t\t\t\t\tconfig.devtool = 'eval-source-map';\n\t\t\t\t\tconfig.plugins?.push(new EsbuildPlugin());\n\t\t\t\t},\n\t\t\t\twebpack,\n\t\t\t);\n\n\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\t\t});\n\n\t\ttest('no warning when define is empty with eval devtool', async () => {\n\t\t\tconst built = await build(\n\t\t\t\tfixtures.minification,\n\t\t\t\t(config) => {\n\t\t\t\t\tconfig.devtool = 'eval-source-map';\n\t\t\t\t\tconfig.plugins?.push(\n\t\t\t\t\t\tnew EsbuildPlugin({\n\t\t\t\t\t\t\tdefine: {},\n\t\t\t\t\t\t}),\n\t\t\t\t\t);\n\t\t\t\t},\n\t\t\t\twebpack,\n\t\t\t);\n\n\t\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\t\texpect(built.stats.hasErrors()).toBe(false);\n\t\t});\n\t});\n};\n"
  },
  {
    "path": "tests/specs/tsconfig.ts",
    "content": "import path from 'path';\nimport { createRequire } from 'node:module';\nimport { describe, test, expect } from 'manten';\nimport { createFixture } from 'fs-fixture';\nimport { execa } from 'execa';\nimport { tsconfigJson } from '../utils.js';\n\nconst require = createRequire(import.meta.url);\n\nconst webpackCli = path.resolve('node_modules/webpack-cli/bin/cli.js');\nconst esbuildLoader = path.resolve('dist/index.cjs');\n\nconst detectStrictMode = '(function() { return !this; })()';\n\ndescribe('tsconfig', () => {\n\tdescribe('loader', () => {\n\t\ttest('auto-detects tsconfig and applies to all files regardless of include patterns', async () => {\n\t\t\tawait using fixture = await createFixture({\n\t\t\t\tsrc: {\n\t\t\t\t\t'index.ts': `module.exports = [\n\t\t\t\t\t\t\t${detectStrictMode},\n\t\t\t\t\t\t\trequire(\"./lib.ts\"),\n\t\t\t\t\t\t\trequire(\"./nested/also-strict.ts\"),\n\t\t\t\t\t\t];`,\n\t\t\t\t\t'lib.ts': `module.exports = ${detectStrictMode}`,\n\t\t\t\t\tnested: {\n\t\t\t\t\t\t'also-strict.ts': `module.exports = ${detectStrictMode}`,\n\t\t\t\t\t\t'tsconfig.json': tsconfigJson({\n\t\t\t\t\t\t\tcompilerOptions: {\n\t\t\t\t\t\t\t\tstrict: true,\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t}),\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t\t'webpack.config.js': `\n\t\t\t\t\tmodule.exports = {\n\t\t\t\t\t\tmode: 'production',\n\n\t\t\t\t\t\toptimization: {\n\t\t\t\t\t\t\tminimize: false,\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tresolveLoader: {\n\t\t\t\t\t\t\talias: {\n\t\t\t\t\t\t\t\t'esbuild-loader': ${JSON.stringify(esbuildLoader)},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tmodule: {\n\t\t\t\t\t\t\trules: [{\n\t\t\t\t\t\t\t\ttest: /\\\\.ts$/,\n\t\t\t\t\t\t\t\tloader: 'esbuild-loader',\n\t\t\t\t\t\t\t}],\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tentry: './src/index.ts',\n\n\t\t\t\t\t\toutput: {\n\t\t\t\t\t\t\tlibraryTarget: 'commonjs2',\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t\t`,\n\t\t\t\t'tsconfig.json': tsconfigJson({\n\t\t\t\t\tcompilerOptions: {\n\t\t\t\t\t\tstrict: true,\n\t\t\t\t\t},\n\t\t\t\t\tinclude: [\n\t\t\t\t\t\t'src/index.ts',\n\t\t\t\t\t],\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\tawait execa(webpackCli, {\n\t\t\t\tcwd: fixture.path,\n\t\t\t});\n\n\t\t\t// All files get strict mode from their nearest tsconfig\n\t\t\t// lib.ts is NOT in include pattern but still gets strict mode\n\t\t\texpect(\n\t\t\t\trequire(path.join(fixture.path, 'dist/main.js')),\n\t\t\t).toStrictEqual([true, true, true]);\n\t\t});\n\n\t\ttest('handles resource with query string', async () => {\n\t\t\tawait using fixture = await createFixture({\n\t\t\t\tsrc: {\n\t\t\t\t\t'index.ts': `module.exports = [${detectStrictMode}, require(\"./lib.ts?some-query\")];`,\n\t\t\t\t\t'lib.ts': `module.exports = ${detectStrictMode}`,\n\t\t\t\t},\n\t\t\t\t'webpack.config.js': `\n\t\t\t\t\tmodule.exports = {\n\t\t\t\t\t\tmode: 'production',\n\n\t\t\t\t\t\toptimization: {\n\t\t\t\t\t\t\tminimize: false,\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tresolveLoader: {\n\t\t\t\t\t\t\talias: {\n\t\t\t\t\t\t\t\t'esbuild-loader': ${JSON.stringify(esbuildLoader)},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tmodule: {\n\t\t\t\t\t\t\trules: [{\n\t\t\t\t\t\t\t\ttest: /\\\\.ts$/,\n\t\t\t\t\t\t\t\tloader: 'esbuild-loader',\n\t\t\t\t\t\t\t}],\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tentry: './src/index.ts',\n\n\t\t\t\t\t\toutput: {\n\t\t\t\t\t\t\tlibraryTarget: 'commonjs2',\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t\t`,\n\t\t\t\t'tsconfig.json': tsconfigJson({\n\t\t\t\t\tcompilerOptions: {\n\t\t\t\t\t\tstrict: true,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\tawait execa(webpackCli, {\n\t\t\t\tcwd: fixture.path,\n\t\t\t});\n\n\t\t\t// Both files get strict mode even with query string in require\n\t\t\texpect(\n\t\t\t\trequire(path.join(fixture.path, 'dist/main.js')),\n\t\t\t).toStrictEqual([true, true]);\n\t\t});\n\n\t\ttest('applies custom tsconfig to all files regardless of include patterns', async () => {\n\t\t\tawait using fixture = await createFixture({\n\t\t\t\tsrc: {\n\t\t\t\t\t'utils/lib.ts': `module.exports = ${detectStrictMode}`,\n\t\t\t\t\t'app/index.ts': `module.exports = [${detectStrictMode}, require(\"../utils/lib.ts\")];`,\n\t\t\t\t},\n\t\t\t\t'webpack.config.js': `\n\t\t\t\t\tmodule.exports = {\n\t\t\t\t\t\tmode: 'production',\n\n\t\t\t\t\t\toptimization: {\n\t\t\t\t\t\t\tminimize: false,\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tresolveLoader: {\n\t\t\t\t\t\t\talias: {\n\t\t\t\t\t\t\t\t'esbuild-loader': ${JSON.stringify(esbuildLoader)},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tmodule: {\n\t\t\t\t\t\t\trules: [{\n\t\t\t\t\t\t\t\ttest: /\\\\.ts$/,\n\t\t\t\t\t\t\t\tloader: 'esbuild-loader',\n\t\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\t\ttsconfig: './tsconfig.json',\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t}],\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tentry: './src/app/index.ts',\n\n\t\t\t\t\t\toutput: {\n\t\t\t\t\t\t\tlibraryTarget: 'commonjs2',\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t\t`,\n\t\t\t\t'tsconfig.json': tsconfigJson({\n\t\t\t\t\tcompilerOptions: {\n\t\t\t\t\t\tstrict: true,\n\t\t\t\t\t},\n\t\t\t\t\tinclude: [\n\t\t\t\t\t\t'src/app/**/*',\n\t\t\t\t\t],\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\tconst { stdout, exitCode } = await execa(webpackCli, {\n\t\t\t\tcwd: fixture.path,\n\t\t\t});\n\n\t\t\t// Should NOT produce warnings even though lib.ts is not in include patterns\n\t\t\t// TypeScript applies tsconfig to all imports\n\t\t\texpect(stdout).not.toMatch('does not match its \"include\" patterns');\n\t\t\texpect(exitCode).toBe(0);\n\n\t\t\t// Both files should have strict mode applied\n\t\t\texpect(\n\t\t\t\trequire(path.join(fixture.path, 'dist/main.js')),\n\t\t\t).toStrictEqual([true, true]);\n\t\t});\n\n\t\ttest('applies different tsconfig.json paths', async () => {\n\t\t\tawait using fixture = await createFixture({\n\t\t\t\tsrc: {\n\t\t\t\t\t'index.ts': 'export class C { foo = 100; }',\n\t\t\t\t\t'index2.ts': 'export class C { foo = 100; }',\n\t\t\t\t},\n\t\t\t\t'webpack.config.js': `\n\t\t\t\t\tmodule.exports = {\n\t\t\t\t\t\tmode: 'production',\n\n\t\t\t\t\t\toptimization: {\n\t\t\t\t\t\t\tminimize: false,\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tresolveLoader: {\n\t\t\t\t\t\t\talias: {\n\t\t\t\t\t\t\t\t'esbuild-loader': ${JSON.stringify(esbuildLoader)},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tmodule: {\n\t\t\t\t\t\t\trules: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttest: /index\\\\.ts$/,\n\t\t\t\t\t\t\t\t\tloader: 'esbuild-loader',\n\t\t\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\t\t\ttsconfig: './tsconfig.custom1.json',\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t},\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttest: /index2\\\\.ts$/,\n\t\t\t\t\t\t\t\t\tloader: 'esbuild-loader',\n\t\t\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\t\t\ttsconfig: './tsconfig.custom2.json',\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tentry: {\n\t\t\t\t\t\t\tindex1: './src/index.ts',\n\t\t\t\t\t\t\tindex2: './src/index2.ts',\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\toutput: {\n\t\t\t\t\t\t\tlibraryTarget: 'commonjs2',\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t\t`,\n\t\t\t\t'tsconfig.custom1.json': tsconfigJson({\n\t\t\t\t\tcompilerOptions: {\n\t\t\t\t\t\tuseDefineForClassFields: false,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t\t'tsconfig.custom2.json': tsconfigJson({\n\t\t\t\t\tcompilerOptions: {\n\t\t\t\t\t\tuseDefineForClassFields: true,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\tawait execa(webpackCli, {\n\t\t\t\tcwd: fixture.path,\n\t\t\t});\n\n\t\t\tconst code1 = await fixture.readFile('dist/index1.js', 'utf8');\n\t\t\texpect(code1).toMatch('this.foo = 100;');\n\n\t\t\tconst code2 = await fixture.readFile('dist/index2.js', 'utf8');\n\t\t\texpect(code2).toMatch('__publicField(this, \"foo\", 100);');\n\t\t});\n\n\t\ttest('fails on invalid tsconfig.json', async () => {\n\t\t\tawait using fixture = await createFixture({\n\t\t\t\t'tsconfig.json': tsconfigJson({\n\t\t\t\t\textends: 'unresolvable-dep',\n\t\t\t\t}),\n\t\t\t\tsrc: {\n\t\t\t\t\t'index.ts': `\n\t\t\t\t\t\tconsole.log('Hello, world!' as numer);\n\t\t\t\t\t\t`,\n\t\t\t\t},\n\t\t\t\t'webpack.config.js': `\n\t\t\t\t\tmodule.exports = {\n\t\t\t\t\t\tmode: 'production',\n\n\t\t\t\t\t\toptimization: {\n\t\t\t\t\t\t\tminimize: false,\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tresolveLoader: {\n\t\t\t\t\t\t\talias: {\n\t\t\t\t\t\t\t\t'esbuild-loader': ${JSON.stringify(esbuildLoader)},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tresolve: {\n\t\t\t\t\t\t\textensions: ['.ts', '.js'],\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tmodule: {\n\t\t\t\t\t\t\trules: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttest: /.[tj]sx?$/,\n\t\t\t\t\t\t\t\t\tloader: 'esbuild-loader',\n\t\t\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\t\t\ttarget: 'es2015',\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tentry: {\n\t\t\t\t\t\t\tindex: './src/index.ts',\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t\t`,\n\t\t\t});\n\n\t\t\tconst { stdout, exitCode } = await execa(webpackCli, {\n\t\t\t\tcwd: fixture.path,\n\t\t\t\treject: false,\n\t\t\t});\n\n\t\t\texpect(stdout).toMatch('Error parsing tsconfig.json:\\nFile \\'unresolvable-dep\\' not found.');\n\t\t\texpect(exitCode).toBe(1);\n\t\t});\n\n\t\ttest('ignores invalid tsconfig.json in JS dependencies', async () => {\n\t\t\tawait using fixture = await createFixture({\n\t\t\t\t'node_modules/fake-lib': {\n\t\t\t\t\t'package.json': JSON.stringify({\n\t\t\t\t\t\tname: 'fake-lib',\n\t\t\t\t\t}),\n\t\t\t\t\t'tsconfig.json': tsconfigJson({\n\t\t\t\t\t\textends: 'unresolvable-dep',\n\t\t\t\t\t}),\n\t\t\t\t\t'index.js': 'export function testFn() { return \"Hi!\" }',\n\t\t\t\t},\n\t\t\t\t'src/index.ts': `\n\t\t\t\t\timport { testFn } from \"fake-lib\";\n\t\t\t\t\ttestFn();\n\t\t\t\t\t`,\n\t\t\t\t'webpack.config.js': `\n\t\t\t\t\tmodule.exports = {\n\t\t\t\t\t\tmode: 'production',\n\n\t\t\t\t\t\toptimization: {\n\t\t\t\t\t\t\tminimize: false,\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tresolveLoader: {\n\t\t\t\t\t\t\talias: {\n\t\t\t\t\t\t\t\t'esbuild-loader': ${JSON.stringify(esbuildLoader)},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tresolve: {\n\t\t\t\t\t\t\textensions: ['.ts', '.js'],\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tmodule: {\n\t\t\t\t\t\t\trules: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttest: /.[tj]sx?$/,\n\t\t\t\t\t\t\t\t\tloader: 'esbuild-loader',\n\t\t\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\t\t\ttarget: 'es2015',\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tentry: {\n\t\t\t\t\t\t\tindex: './src/index.ts',\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t\t`,\n\t\t\t});\n\n\t\t\tconst { stdout, exitCode } = await execa(webpackCli, {\n\t\t\t\tcwd: fixture.path,\n\t\t\t});\n\n\t\t\texpect(stdout).not.toMatch('Error parsing tsconfig.json');\n\t\t\texpect(exitCode).toBe(0);\n\t\t});\n\n\t\ttest('warns on invalid tsconfig.json in TS dependencies', async () => {\n\t\t\tawait using fixture = await createFixture({\n\t\t\t\t'node_modules/fake-lib': {\n\t\t\t\t\t'package.json': JSON.stringify({\n\t\t\t\t\t\tname: 'fake-lib',\n\t\t\t\t\t}),\n\t\t\t\t\t'tsconfig.json': tsconfigJson({\n\t\t\t\t\t\textends: 'unresolvable-dep',\n\t\t\t\t\t}),\n\t\t\t\t\t'index.ts': 'export function testFn(): string { return \"Hi!\" }',\n\t\t\t\t},\n\t\t\t\t'src/index.ts': `\n\t\t\t\t\timport { testFn } from \"fake-lib\";\n\t\t\t\t\ttestFn();\n\t\t\t\t\t`,\n\t\t\t\t'webpack.config.js': `\n\t\t\t\t\tmodule.exports = {\n\t\t\t\t\t\tmode: 'production',\n\n\t\t\t\t\t\toptimization: {\n\t\t\t\t\t\t\tminimize: false,\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tresolveLoader: {\n\t\t\t\t\t\t\talias: {\n\t\t\t\t\t\t\t\t'esbuild-loader': ${JSON.stringify(esbuildLoader)},\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tresolve: {\n\t\t\t\t\t\t\textensions: ['.ts', '.js'],\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tmodule: {\n\t\t\t\t\t\t\trules: [\n\t\t\t\t\t\t\t\t{\n\t\t\t\t\t\t\t\t\ttest: /.[tj]sx?$/,\n\t\t\t\t\t\t\t\t\tloader: 'esbuild-loader',\n\t\t\t\t\t\t\t\t\toptions: {\n\t\t\t\t\t\t\t\t\t\ttarget: 'es2015',\n\t\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t},\n\n\t\t\t\t\t\tentry: {\n\t\t\t\t\t\t\tindex: './src/index.ts',\n\t\t\t\t\t\t},\n\t\t\t\t\t};\n\t\t\t\t\t`,\n\t\t\t});\n\n\t\t\tconst { stdout, exitCode } = await execa(webpackCli, {\n\t\t\t\tcwd: fixture.path,\n\t\t\t});\n\n\t\t\texpect(stdout).toMatch('Error parsing tsconfig.json:\\nFile \\'unresolvable-dep\\' not found.');\n\n\t\t\t// Warning so doesn't fail\n\t\t\texpect(exitCode).toBe(0);\n\t\t});\n\t});\n\n\tdescribe('plugin', () => {\n\t\t/**\n\t\t\t * Since the plugin applies on distribution assets, it should not apply\n\t\t\t * any tsconfig settings.\n\t\t\t */\n\t\ttest('should not detect tsconfig.json and apply strict mode', async () => {\n\t\t\tawait using fixture = await createFixture({\n\t\t\t\tsrc: {\n\t\t\t\t\t'index.js': 'console.log(1)',\n\t\t\t\t},\n\t\t\t\t'webpack.config.js': `\n\t\t\t\t\tconst { EsbuildPlugin } = require(${JSON.stringify(esbuildLoader)});\n\t\t\t\t\tmodule.exports = {\n\t\t\t\t\t\tmode: 'production',\n\t\t\t\t\t\toptimization: {\n\t\t\t\t\t\t\tminimizer: [\n\t\t\t\t\t\t\t\tnew EsbuildPlugin(),\n\t\t\t\t\t\t\t],\n\t\t\t\t\t\t},\n\t\t\t\t\t\tentry: './src/index.js',\n\t\t\t\t\t};\n\t\t\t\t\t`,\n\t\t\t\t'tsconfig.json': tsconfigJson({\n\t\t\t\t\tcompilerOptions: {\n\t\t\t\t\t\tstrict: true,\n\t\t\t\t\t},\n\t\t\t\t}),\n\t\t\t});\n\n\t\t\tawait execa(webpackCli, {\n\t\t\t\tcwd: fixture.path,\n\t\t\t});\n\n\t\t\tconst code = await fixture.readFile('dist/main.js', 'utf8');\n\t\t\texpect(code).not.toMatch('use strict');\n\t\t});\n\t});\n});\n"
  },
  {
    "path": "tests/specs/webpack5.ts",
    "content": "import { describe, test, expect } from 'manten';\nimport { build } from 'webpack-test-utils';\nimport webpack5 from 'webpack5';\nimport { configureEsbuildMinifyPlugin } from '../utils.js';\n\nconst { RawSource } = webpack5.sources;\n\ndescribe('Webpack 5', () => {\n\ttest('Stats', async () => {\n\t\tconst built = await build({ '/src/index.js': '' }, (config) => {\n\t\t\tconfigureEsbuildMinifyPlugin(config);\n\t\t}, webpack5);\n\n\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\texpect(built.stats.hasErrors()).toBe(false);\n\t\texpect(built.stats.toString().includes('[minimized]')).toBe(true);\n\t});\n\n\ttest('Minifies new assets', async () => {\n\t\tconst built = await build({ '/src/index.js': '' }, (config) => {\n\t\t\tconfigureEsbuildMinifyPlugin(config);\n\n\t\t\tconfig.plugins!.push({\n\t\t\t\tapply: (compiler) => {\n\t\t\t\t\tcompiler.hooks.compilation.tap('test', (compilation) => {\n\t\t\t\t\t\tcompilation.hooks.processAssets.tap(\n\t\t\t\t\t\t\t{ name: 'test' },\n\t\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\t\tcompilation.emitAsset(\n\t\t\t\t\t\t\t\t\t'test.js',\n\t\t\t\t\t\t\t\t\tnew RawSource('const value = 1;\\n\\nexport default value;'),\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t});\n\t\t}, webpack5);\n\n\t\texpect(built.stats.hasWarnings()).toBe(false);\n\t\texpect(built.stats.hasErrors()).toBe(false);\n\n\t\tconst asset = built.stats.compilation.getAsset('test.js');\n\t\texpect(asset!.info.minimized).toBe(true);\n\n\t\tconst file = built.fs.readFileSync('/dist/test.js', 'utf8');\n\t\texpect(file).toBe('const e=1;export default 1;\\n');\n\t});\n\n\ttest('Doesnt minify minimized assets', async () => {\n\t\tlet sourceAndMapCalled = false;\n\t\tawait build({ '/src/index.js': '' }, (config) => {\n\t\t\tconfigureEsbuildMinifyPlugin(config);\n\n\t\t\tconfig.plugins!.push({\n\t\t\t\tapply: (compiler) => {\n\t\t\t\t\tcompiler.hooks.compilation.tap('test', (compilation) => {\n\t\t\t\t\t\tcompilation.hooks.processAssets.tap(\n\t\t\t\t\t\t\t{ name: 'test' },\n\t\t\t\t\t\t\t() => {\n\t\t\t\t\t\t\t\tconst asset = new RawSource('');\n\n\t\t\t\t\t\t\t\t// @ts-expect-error overwriting to make sure it's not called\n\t\t\t\t\t\t\t\tasset.sourceAndMap = () => {\n\t\t\t\t\t\t\t\t\tsourceAndMapCalled = true;\n\t\t\t\t\t\t\t\t};\n\n\t\t\t\t\t\t\t\tcompilation.emitAsset(\n\t\t\t\t\t\t\t\t\t'test.js',\n\t\t\t\t\t\t\t\t\tasset,\n\t\t\t\t\t\t\t\t\t{ minimized: true },\n\t\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\t},\n\t\t\t\t\t\t);\n\t\t\t\t\t});\n\t\t\t\t},\n\t\t\t});\n\t\t}, webpack5);\n\n\t\texpect(sourceAndMapCalled).toBe(false);\n\t});\n});\n"
  },
  {
    "path": "tests/utils.ts",
    "content": "import path from 'path';\nimport type webpack4 from 'webpack';\nimport type webpack5 from 'webpack5';\nimport MiniCssExtractPlugin from 'mini-css-extract-plugin';\nimport type { TsConfigJson } from 'get-tsconfig';\nimport { EsbuildPlugin, type EsbuildPluginOptions } from '#esbuild-loader';\n\nconst esbuildLoaderPath = path.resolve('./dist/index.cjs');\n\ntype Webpack4 = typeof webpack4;\n\ntype Webpack5 = typeof webpack5;\n\nexport type Webpack = Webpack4 & Webpack5;\n\nexport type WebpackConfiguration = webpack4.Configuration | webpack5.Configuration;\n\ntype RuleSetUseItem = webpack4.RuleSetUseItem & webpack5.RuleSetUseItem;\n\ntype RuleSetRule = webpack4.RuleSetRule & webpack5.RuleSetRule;\n\nexport const isWebpack4 = (\n\twebpack: Webpack4 | Webpack5,\n): webpack is Webpack4 => Boolean(webpack.version?.startsWith('4.'));\n\nexport const configureEsbuildLoader = (\n\tconfig: WebpackConfiguration,\n\trulesConfig?: RuleSetRule,\n) => {\n\tconfig.resolveLoader!.alias = {\n\t\t'esbuild-loader': esbuildLoaderPath,\n\t};\n\n\tconfig.module!.rules!.push({\n\t\ttest: /\\.js$/,\n\t\tloader: 'esbuild-loader',\n\t\t...rulesConfig,\n\t\toptions: {\n\t\t\ttsconfigRaw: undefined,\n\t\t\t...(\n\t\t\t\ttypeof rulesConfig?.options === 'object'\n\t\t\t\t\t? rulesConfig.options\n\t\t\t\t\t: {}\n\t\t\t),\n\t\t},\n\t});\n};\n\nexport const configureEsbuildMinifyPlugin = (\n\tconfig: WebpackConfiguration,\n\toptions?: EsbuildPluginOptions,\n) => {\n\tconfig.optimization = {\n\t\tminimize: true,\n\t\tminimizer: [\n\t\t\tnew EsbuildPlugin({\n\t\t\t\ttsconfigRaw: undefined,\n\t\t\t\t...options,\n\t\t\t}),\n\t\t],\n\t};\n};\n\nexport const configureCssLoader = (\n\tconfig: WebpackConfiguration,\n) => {\n\tconst cssRule = {\n\t\ttest: /\\.css$/,\n\t\tuse: [\n\t\t\t'css-loader',\n\t\t] as RuleSetUseItem[],\n\t};\n\tconfig.module!.rules!.push(cssRule);\n\treturn cssRule;\n};\n\nexport const configureMiniCssExtractPlugin = (\n\tconfig: WebpackConfiguration,\n) => {\n\tconst cssRule = configureCssLoader(config);\n\tcssRule.use.unshift(MiniCssExtractPlugin.loader);\n\n\tconfig.plugins!.push(\n\t\t// @ts-expect-error Forcing it to Webpack 5\n\t\tnew MiniCssExtractPlugin(),\n\t);\n};\n\nexport const tsconfigJson = (\n\ttsconfigObject: TsConfigJson,\n) => JSON.stringify(tsconfigObject);\n"
  },
  {
    "path": "tsconfig.json",
    "content": "{\n\t\"compilerOptions\": {\n\t\t\"target\": \"es2022\",\n\t\t\"lib\": [\n\t\t\t\"ESNext\",\n\t\t],\n\t\t\"moduleDetection\": \"force\",\n\n\t\t\"module\": \"preserve\",\n\t\t\"resolveJsonModule\": true,\n\t\t\"allowJs\": true,\n\t\t\"strict\": true,\n\t\t// \"noUncheckedIndexedAccess\": true,\n\t\t\"noImplicitOverride\": true,\n\t\t\"noEmit\": true,\n\t\t\"esModuleInterop\": true,\n\t\t\"verbatimModuleSyntax\": true,\n\t\t\"skipLibCheck\": true,\n\t},\n}\n"
  }
]