├── version.txt ├── test ├── fixtures │ ├── resolveDirectory │ │ ├── fakeImage.png │ │ ├── entry.js │ │ └── resDir.svelte │ ├── watch-preprocessing │ │ ├── external.scss │ │ ├── entry.js │ │ └── external-styles.svelte │ ├── preprocessing-sourcemaps │ │ ├── sourcemapImport.scss │ │ ├── pp-sourcemaps.js │ │ ├── svelte.config.js │ │ └── pp-sourcemaps.svelte │ ├── svelte5 │ │ ├── javascript-modules │ │ │ ├── module.svelte.js │ │ │ ├── entry.js │ │ │ └── svelte5.svelte │ │ ├── typescript-modules │ │ │ ├── module.svelte.ts │ │ │ ├── entry.ts │ │ │ └── svelte5.svelte │ │ ├── entry.js │ │ └── svelte5.svelte │ ├── errors │ │ ├── entry.js │ │ ├── svelte.config.js │ │ └── error.svelte │ ├── include │ │ ├── entry.js │ │ └── include.notSvelte │ ├── non-ascii │ │ ├── entry.js │ │ └── non-ascii.svelte │ ├── warnings │ │ ├── entry.js │ │ └── missing-declaration.svelte │ └── ts-module-minification │ │ ├── entry.ts │ │ ├── svelte5.svelte │ │ └── module.svelte.ts ├── versionTests │ ├── .gitignore │ ├── entry.js │ ├── entry5.js │ ├── index.svelte │ ├── versionTests.sh │ └── test.js ├── utils │ ├── commonOptions.js │ └── scss-preprocess.mjs ├── includeOption.mjs ├── resolveDirectoryTest.mjs ├── non-ascii.mjs ├── errors.mjs ├── sourcemapsTest.mjs ├── watchPreprocessingTest.mjs ├── cacheTest.mjs ├── warnings.mjs ├── svelte5.mjs └── simpleTest.mjs ├── example-js ├── .gitignore ├── test.svelte.js ├── entry.js ├── package.json ├── index.html ├── second.svelte ├── index.svelte └── buildscript.js ├── example-ts ├── .gitignore ├── test.svelte.ts ├── fun.ts ├── entry.ts ├── index.html ├── second.svelte ├── package.json ├── index.svelte ├── buildscript.js └── tsconfig.json ├── .prettierignore ├── .prettierrc ├── .gitignore ├── .github ├── dependabot.yml ├── ISSUE_TEMPLATE │ ├── feature_request.md │ └── bug_report.md └── workflows │ ├── release.yml │ └── ci.yml ├── tsconfig.json ├── LICENCE ├── dist └── index.d.ts ├── package.json ├── README.md ├── CHANGELOG.md └── index.ts /version.txt: -------------------------------------------------------------------------------- 1 | 0.9.4 2 | -------------------------------------------------------------------------------- /test/fixtures/resolveDirectory/fakeImage.png: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /example-js/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | *.log 3 | *lock.json 4 | -------------------------------------------------------------------------------- /example-ts/.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | *.log 3 | *lock.json 4 | -------------------------------------------------------------------------------- /test/versionTests/.gitignore: -------------------------------------------------------------------------------- 1 | dist/ 2 | package** 3 | index.mjs 4 | -------------------------------------------------------------------------------- /test/fixtures/watch-preprocessing/external.scss: -------------------------------------------------------------------------------- 1 | p { 2 | color: red; 3 | } 4 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | package-lock.json 4 | example/package-lock.json 5 | -------------------------------------------------------------------------------- /example-js/test.svelte.js: -------------------------------------------------------------------------------- 1 | export default class Counter { 2 | value = $state(0); 3 | } 4 | -------------------------------------------------------------------------------- /example-ts/test.svelte.ts: -------------------------------------------------------------------------------- 1 | export default class Counter { 2 | value: number = $state(0); 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/preprocessing-sourcemaps/sourcemapImport.scss: -------------------------------------------------------------------------------- 1 | button { 2 | font-size: 1.5rem; 3 | } 4 | -------------------------------------------------------------------------------- /test/fixtures/svelte5/javascript-modules/module.svelte.js: -------------------------------------------------------------------------------- 1 | export const counter = $state({ 2 | count: 0, 3 | }); 4 | -------------------------------------------------------------------------------- /test/fixtures/errors/entry.js: -------------------------------------------------------------------------------- 1 | import Test from "./error.svelte"; 2 | 3 | new Test({ 4 | target: document.body, 5 | }); 6 | -------------------------------------------------------------------------------- /test/versionTests/entry.js: -------------------------------------------------------------------------------- 1 | import Test from "./index.svelte"; 2 | 3 | new Test({ 4 | target: document.body, 5 | }); 6 | -------------------------------------------------------------------------------- /test/fixtures/include/entry.js: -------------------------------------------------------------------------------- 1 | import Test from "./include.notSvelte"; 2 | 3 | new Test({ 4 | target: document.body, 5 | }); 6 | -------------------------------------------------------------------------------- /test/fixtures/non-ascii/entry.js: -------------------------------------------------------------------------------- 1 | import Test from "./non-ascii.svelte"; 2 | 3 | new Test({ 4 | target: document.body, 5 | }); 6 | -------------------------------------------------------------------------------- /test/fixtures/resolveDirectory/entry.js: -------------------------------------------------------------------------------- 1 | import Test from "./resDir.svelte"; 2 | 3 | new Test({ 4 | target: document.body, 5 | }); 6 | -------------------------------------------------------------------------------- /test/fixtures/svelte5/typescript-modules/module.svelte.ts: -------------------------------------------------------------------------------- 1 | export const counter: { count: number } = $state({ 2 | count: 0, 3 | }); 4 | -------------------------------------------------------------------------------- /example-js/entry.js: -------------------------------------------------------------------------------- 1 | import { mount } from "svelte"; 2 | import Test from "./index.svelte"; 3 | 4 | mount(Test, { target: document.body }); 5 | -------------------------------------------------------------------------------- /test/fixtures/warnings/entry.js: -------------------------------------------------------------------------------- 1 | import Test from "./missing-declaration.svelte"; 2 | 3 | new Test({ 4 | target: document.body, 5 | }); 6 | -------------------------------------------------------------------------------- /test/fixtures/watch-preprocessing/entry.js: -------------------------------------------------------------------------------- 1 | import Test from "./external-styles.svelte"; 2 | 3 | new Test({ 4 | target: document.body, 5 | }); 6 | -------------------------------------------------------------------------------- /test/fixtures/preprocessing-sourcemaps/pp-sourcemaps.js: -------------------------------------------------------------------------------- 1 | import Test from "./pp-sourcemaps.svelte"; 2 | 3 | new Test({ 4 | target: document.body, 5 | }); 6 | -------------------------------------------------------------------------------- /test/versionTests/entry5.js: -------------------------------------------------------------------------------- 1 | import { mount } from "svelte"; 2 | import Test from "./index.svelte"; 3 | 4 | mount(Test, { 5 | target: document.body, 6 | }); 7 | -------------------------------------------------------------------------------- /example-ts/fun.ts: -------------------------------------------------------------------------------- 1 | export function haha(): string { 2 | return `hahahahHA!!`; 3 | } 4 | 5 | export type Joke = { 6 | rating: number; 7 | joke: string; 8 | }; 9 | -------------------------------------------------------------------------------- /test/fixtures/svelte5/entry.js: -------------------------------------------------------------------------------- 1 | import { mount } from "svelte"; 2 | import Test from "./svelte5.svelte"; 3 | 4 | const test = mount(Test, { target: document.body }); 5 | -------------------------------------------------------------------------------- /test/fixtures/svelte5/javascript-modules/entry.js: -------------------------------------------------------------------------------- 1 | import { mount } from "svelte"; 2 | import Test from "./svelte5.svelte"; 3 | 4 | const test = mount(Test, { target: document.body }); 5 | -------------------------------------------------------------------------------- /test/fixtures/svelte5/typescript-modules/entry.ts: -------------------------------------------------------------------------------- 1 | import { mount } from "svelte"; 2 | import Test from "./svelte5.svelte"; 3 | 4 | const test = mount(Test, { target: document.body }); 5 | -------------------------------------------------------------------------------- /test/fixtures/ts-module-minification/entry.ts: -------------------------------------------------------------------------------- 1 | import { mount } from "svelte"; 2 | import Test from "./svelte5.svelte"; 3 | 4 | const test = mount(Test, { target: document.body }); 5 | -------------------------------------------------------------------------------- /example-ts/entry.ts: -------------------------------------------------------------------------------- 1 | import Test from "./index.svelte"; 2 | import { haha } from "./fun"; 3 | import { mount } from "svelte"; 4 | 5 | mount(Test, { target: document.body }); 6 | console.log(haha()); 7 | -------------------------------------------------------------------------------- /test/fixtures/watch-preprocessing/external-styles.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 |
6 |

Hello World

7 |

Testing this!

8 |
9 | -------------------------------------------------------------------------------- /test/fixtures/ts-module-minification/svelte5.svelte: -------------------------------------------------------------------------------- 1 | 6 | 7 | 10 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "printWidth": 100, 3 | "tabWidth": 2, 4 | "overrides": [ 5 | { 6 | "files": ["*.js", "*.mjs", "*.ts"], 7 | "options": { 8 | "tabWidth": 4 9 | } 10 | } 11 | ] 12 | } 13 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # duh 2 | **node_modules/ 3 | 4 | #should be built by running `node build.js` fresh every time 5 | dist/index.mjs 6 | dist/index.js 7 | 8 | # from example 9 | example/dist/ 10 | example/package-lock.json 11 | 12 | *.log 13 | -------------------------------------------------------------------------------- /test/fixtures/errors/svelte.config.js: -------------------------------------------------------------------------------- 1 | const { typescript } = require("svelte-preprocess-esbuild"); 2 | const { sass } = require("svelte-preprocess-sass"); 3 | 4 | module.exports = { 5 | preprocess: [{ style: sass() }, typescript()], 6 | }; 7 | -------------------------------------------------------------------------------- /test/fixtures/warnings/missing-declaration.svelte: -------------------------------------------------------------------------------- 1 |
2 | 3 | {#if MY_GLOBAL} 4 | {/if} 5 | 6 | 7 | 8 |
9 | -------------------------------------------------------------------------------- /test/fixtures/preprocessing-sourcemaps/svelte.config.js: -------------------------------------------------------------------------------- 1 | const { typescript } = require("svelte-preprocess-esbuild"); 2 | const { sass } = require("svelte-preprocess-sass"); 3 | 4 | module.exports = { 5 | preprocess: [{ style: sass() }, typescript()], 6 | }; 7 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: "npm" 4 | directory: "/" 5 | schedule: 6 | interval: "weekly" 7 | - package-ecosystem: "github-actions" 8 | directory: "/" 9 | schedule: 10 | interval: "weekly" 11 | -------------------------------------------------------------------------------- /test/fixtures/include/include.notSvelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | 12 |
13 |

Hello World

14 |
15 | -------------------------------------------------------------------------------- /test/fixtures/non-ascii/non-ascii.svelte: -------------------------------------------------------------------------------- 1 | 4 | 5 | 11 | 12 |
13 |

Hello World © 2021 {y}

14 |
15 | -------------------------------------------------------------------------------- /example-js/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "buildscript.js", 3 | "scripts": { 4 | "build": "node buildscript.js" 5 | }, 6 | "dependencies": { 7 | "esbuild": "^0.25.0", 8 | "esbuild-svelte": "^0.8.0", 9 | "svelte": "^5.1.3" 10 | }, 11 | "private": true 12 | } 13 | -------------------------------------------------------------------------------- /test/utils/commonOptions.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | format: "esm", 3 | minify: true, 4 | bundle: true, 5 | splitting: true, 6 | write: false, //Don't write anywhere 7 | mainFields: ["svelte", "browser", "module", "main"], 8 | conditions: ["svelte", "browser"], 9 | }; 10 | -------------------------------------------------------------------------------- /test/fixtures/resolveDirectory/resDir.svelte: -------------------------------------------------------------------------------- 1 | 5 | 6 | 11 | 12 |
13 |

Hello World

14 |
15 | -------------------------------------------------------------------------------- /test/fixtures/svelte5/svelte5.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 15 | -------------------------------------------------------------------------------- /test/fixtures/errors/error.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/fixtures/svelte5/javascript-modules/svelte5.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ES2016", 4 | "module": "commonjs", 5 | "strict": true, 6 | "esModuleInterop": true, 7 | "forceConsistentCasingInFileNames": true, 8 | "declaration": true, 9 | "exactOptionalPropertyTypes": true, 10 | "noUnusedLocals": true 11 | }, 12 | "files": ["index.ts"] 13 | } 14 | -------------------------------------------------------------------------------- /example-js/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | esbuild-svelte Example 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /test/fixtures/svelte5/typescript-modules/svelte5.svelte: -------------------------------------------------------------------------------- 1 | 12 | 13 | 16 | -------------------------------------------------------------------------------- /example-ts/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | esbuild-svelte Typescript Example 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /example-js/second.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /example-ts/second.svelte: -------------------------------------------------------------------------------- 1 | 11 | 12 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /example-ts/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "main": "buildscript.js", 3 | "type": "module", 4 | "scripts": { 5 | "build": "node buildscript.js", 6 | "typecheck": "svelte-check --tsconfig tsconfig.json --fail-on-warnings" 7 | }, 8 | "dependencies": { 9 | "@tsconfig/svelte": "^5.0.2", 10 | "esbuild": "^0.25.0", 11 | "esbuild-svelte": "^0.8.0", 12 | "svelte": "^5.1.3", 13 | "svelte-check": "^4.0.5", 14 | "svelte-preprocess": "^6.0.3", 15 | "typescript": "^5.3.3" 16 | }, 17 | "private": true 18 | } 19 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | title: "" 5 | labels: enhancement 6 | assignees: "" 7 | --- 8 | 9 | **Is your feature request related to a problem? Please describe.** 10 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...] 11 | 12 | **Describe the solution you'd like** 13 | A clear and concise description of what you want to happen. 14 | 15 | **Describe alternatives you've considered** 16 | A clear and concise description of any alternative solutions or features you've considered. 17 | 18 | **Additional context** 19 | Add any other context or screenshots about the feature request here. 20 | -------------------------------------------------------------------------------- /test/versionTests/index.svelte: -------------------------------------------------------------------------------- 1 | 9 | 10 | 21 | 22 |
23 | 25 | 26 |
27 | 28 |
29 | 30 |

Hello World © 2021 {y}

31 |
32 | -------------------------------------------------------------------------------- /test/includeOption.mjs: -------------------------------------------------------------------------------- 1 | import { test } from "uvu"; 2 | import * as assert from "uvu/assert"; 3 | import { build } from "esbuild"; 4 | import sveltePlugin from "../dist/index.mjs"; 5 | import commonOptions from "./utils/commonOptions.js"; 6 | 7 | test("Include option works correctly", async () => { 8 | const results = await build({ 9 | ...commonOptions, 10 | entryPoints: ["./test/fixtures/include/entry.js"], 11 | outdir: "../example/dist", 12 | sourcemap: "inline", 13 | plugins: [ 14 | sveltePlugin({ 15 | include: /\.notSvelte$/, 16 | }), 17 | ], 18 | }); 19 | 20 | assert.equal(results.errors.length, 0, "Expected zero errors"); 21 | assert.equal(results.warnings.length, 0, "Expected zero warnings"); 22 | assert.equal(results.outputFiles.length, 1, "Expected a single output file"); 23 | }); 24 | 25 | test.run(); 26 | -------------------------------------------------------------------------------- /example-js/index.svelte: -------------------------------------------------------------------------------- 1 | 13 | 14 | 25 | 26 |
27 | 29 | 30 |
31 | 32 |
33 | 34 | 35 | 36 | {counter.value} 37 | 38 | 39 |
40 | -------------------------------------------------------------------------------- /.github/workflows/release.yml: -------------------------------------------------------------------------------- 1 | name: Release 2 | 3 | on: 4 | push: 5 | tags: ["v*"] 6 | 7 | permissions: 8 | contents: write 9 | 10 | jobs: 11 | release: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - name: Checkout code 15 | uses: actions/checkout@v6 16 | 17 | - name: Extract changelog 18 | run: | 19 | CHANGELOG=$(awk -v ver=$(cat version.txt) '/^## / { if (p) { exit }; if ($2 == ver) { p=1; next} } p' CHANGELOG.md) 20 | echo "CHANGELOG<> $GITHUB_ENV 21 | echo "$CHANGELOG" >> $GITHUB_ENV 22 | echo "EOF" >> $GITHUB_ENV 23 | 24 | - name: Create GitHub Release 25 | uses: actions/create-release@v1 26 | env: 27 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} 28 | with: 29 | tag_name: ${{ github.ref }} 30 | release_name: ${{ github.ref }} 31 | body: ${{ env.CHANGELOG }} 32 | draft: false 33 | prerelease: false 34 | -------------------------------------------------------------------------------- /test/utils/scss-preprocess.mjs: -------------------------------------------------------------------------------- 1 | import { dirname } from "path"; 2 | import { pathToFileURL, fileURLToPath } from "url"; 3 | import * as sassCompiler from "sass"; 4 | 5 | export function sass() { 6 | return function ({ filename, content, attributes }) { 7 | if ( 8 | !( 9 | attributes.type?.includes("text/scss") || 10 | attributes.lang?.includes("scss") || 11 | attributes.type?.includes("text/sass") || 12 | attributes.lang?.includes("sass") 13 | ) 14 | ) { 15 | return null; 16 | } 17 | const { css, sourceMap, loadedUrls } = sassCompiler.compileString(content, { 18 | url: pathToFileURL(filename), 19 | loadPaths: [dirname(filename)], 20 | }); 21 | return { 22 | code: css.toString(), 23 | sourceMap, 24 | dependencies: loadedUrls.map((url) => fileURLToPath(url)), 25 | }; 26 | }; 27 | } 28 | -------------------------------------------------------------------------------- /test/fixtures/preprocessing-sourcemaps/pp-sourcemaps.svelte: -------------------------------------------------------------------------------- 1 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 36 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Report something that isn't working correctly 4 | title: "" 5 | labels: bug 6 | assignees: "" 7 | --- 8 | 9 | **Describe the bug** 10 | A clear and concise description of what the bug is. 11 | 12 | **To Reproduce** 13 | Steps to reproduce the behavior: 14 | 15 | 1. Have a file with `foo` content 16 | 2. Use a build script that looks like `bar` 17 | 3. See error `invalid foobar` 18 | 19 | If you are able to point to a public repostory that reproduces the issue, please list that as well. 20 | 21 | **Expected behavior** 22 | A clear and concise description of what you expected to happen. 23 | 24 | **Screenshots** 25 | If applicable, add screenshots to help explain your problem. 26 | 27 | **Environment (please complete the following information):** 28 | 29 | - esbuild-svelte version: 30 | - esbuild version: 31 | - Svelte version: 32 | - Svelte preprocessors used and their versions (if any): 33 | 34 | **Additional context** 35 | Add any other context about the problem here. 36 | -------------------------------------------------------------------------------- /LICENCE: -------------------------------------------------------------------------------- 1 | Copyright © 2020 Ethan Hampton 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /example-js/buildscript.js: -------------------------------------------------------------------------------- 1 | const fs = require("fs"); 2 | const esbuild = require("esbuild"); 3 | const sveltePlugin = require("esbuild-svelte"); 4 | 5 | //make sure the directoy exists before stuff gets put into it 6 | if (!fs.existsSync("./dist/")) { 7 | fs.mkdirSync("./dist/"); 8 | } 9 | 10 | //build the application 11 | esbuild 12 | .build({ 13 | entryPoints: ["./entry.js"], 14 | mainFields: ["svelte", "browser", "module", "main"], 15 | conditions: ["svelte", "browser"], 16 | outdir: "./dist", 17 | format: "esm", 18 | logLevel: "info", 19 | minify: false, //so the resulting code is easier to understand 20 | bundle: true, 21 | splitting: true, 22 | sourcemap: "inline", 23 | plugins: [sveltePlugin()], 24 | }) 25 | .catch((err) => { 26 | console.error(err); 27 | process.exit(1); 28 | }); 29 | 30 | //use a basic html file to test with 31 | fs.copyFile("./index.html", "./dist/index.html", (err) => { 32 | if (err) throw err; 33 | }); 34 | -------------------------------------------------------------------------------- /test/versionTests/versionTests.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Test esbuild and svelte versions for compability using the example-js project files 4 | 5 | # cd to script directory 6 | cd "$(dirname "$0")" || exit 7 | 8 | # copy esbuild-svelte to destination 9 | cp ../../dist/index.mjs . 10 | 11 | npm init -y || exit 12 | npm pkg set type="module" || exit 13 | 14 | # array of versions 15 | ESBUILD_VERSIONS=("0.17.19" "0.18.10" "0.19.2" "0.21.3" "0.24.0") 16 | SVELTE_VERSIONS=("4.2.1" "5.0.3" "5.1.3") 17 | 18 | # loop through versions 19 | for ESBUILD_VERSION in "${ESBUILD_VERSIONS[@]}" 20 | do 21 | for SVELTE_VERSION in "${SVELTE_VERSIONS[@]}" 22 | do 23 | echo "Testing esbuild@$ESBUILD_VERSION and svelte@$SVELTE_VERSION" 24 | 25 | # install esbuild and svelte versions 26 | npm install esbuild@"$ESBUILD_VERSION" svelte@"$SVELTE_VERSION" || exit 27 | 28 | # run test script 29 | node test.js "$ESBUILD_VERSION" "$SVELTE_VERSION" || exit 30 | done 31 | done 32 | 33 | # remove temp files 34 | rm index.mjs package.json package-lock.json 35 | rm -r dist/ node_modules/ 36 | -------------------------------------------------------------------------------- /test/resolveDirectoryTest.mjs: -------------------------------------------------------------------------------- 1 | import { test } from "uvu"; 2 | import * as assert from "uvu/assert"; 3 | import { build as _build } from "esbuild"; 4 | import { sass } from "./utils/scss-preprocess.mjs"; 5 | import sveltePlugin from "../dist/index.mjs"; 6 | import commonOptions from "./utils/commonOptions.js"; 7 | 8 | test("Fake CSS returns correct resolve directory", async () => { 9 | //more advanced 10 | const results = await _build({ 11 | ...commonOptions, 12 | entryPoints: ["./test/fixtures/resolveDirectory/entry.js"], 13 | outdir: "../example/dist", 14 | sourcemap: "inline", 15 | loader: { 16 | ".png": "file", 17 | }, 18 | plugins: [ 19 | sveltePlugin({ 20 | preprocess: { 21 | style: sass(), 22 | }, 23 | }), 24 | ], 25 | }); 26 | 27 | assert.ok(results.errors.length === 0, "Non-zero number of errors"); 28 | assert.ok(results.warnings.length === 0, "Non-zero number of warnings"); 29 | assert.ok(results.outputFiles.length === 3, "Non-expected number of output files"); 30 | }); 31 | 32 | test.run(); 33 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: 4 | push: 5 | branches: [main] 6 | pull_request: 7 | branches: [main] 8 | 9 | jobs: 10 | build: 11 | runs-on: ubuntu-latest 12 | needs: lint 13 | 14 | strategy: 15 | matrix: 16 | node-version: [18, 20, 22] 17 | 18 | steps: 19 | - uses: actions/checkout@v6 20 | - name: Use Node.js ${{ matrix.node-version }} 21 | uses: actions/setup-node@v6 22 | with: 23 | node-version: ${{ matrix.node-version }} 24 | cache: "npm" 25 | 26 | # Now install and run tests 27 | - run: npm ci 28 | - run: npm run build 29 | - run: npm test 30 | 31 | # Run lint and version tests as it's own job (also sets up caching of npm packages) 32 | lint: 33 | runs-on: ubuntu-latest 34 | 35 | steps: 36 | - uses: actions/checkout@v6 37 | - name: Use Node.js 20 38 | uses: actions/setup-node@v6 39 | with: 40 | node-version: 20 41 | cache: "npm" 42 | 43 | # Now install packages and lint 44 | - run: npm ci 45 | - run: npm run lint 46 | 47 | # now build and run compatibility tests 48 | - run: npm run build 49 | - run: npm run test:compatibility 50 | -------------------------------------------------------------------------------- /test/non-ascii.mjs: -------------------------------------------------------------------------------- 1 | import { test } from "uvu"; 2 | import * as assert from "uvu/assert"; 3 | import { build as _build } from "esbuild"; 4 | import { typescript } from "svelte-preprocess-esbuild"; 5 | import sveltePlugin from "../dist/index.mjs"; 6 | import commonOptions from "./utils/commonOptions.js"; 7 | 8 | test("Can handle special characters in files", async () => { 9 | try { 10 | const results = await _build({ 11 | ...commonOptions, 12 | entryPoints: ["./test/fixtures/non-ascii/entry.js"], 13 | outdir: "../example/dist", 14 | sourcemap: true, 15 | plugins: [ 16 | sveltePlugin({ 17 | preprocess: typescript(), 18 | compilerOptions: { dev: true }, 19 | }), 20 | ], 21 | logLevel: "silent", 22 | }); 23 | assert.ok(true, "Should not have triggered exception"); 24 | assert.equal(results.warnings.length, 0, "Should not have warnings"); 25 | assert.equal(results.errors.length, 0, "Should not have errors"); 26 | } catch (err) { 27 | console.error(err.errors); 28 | assert.not.ok(err.errors, "Should not error because of invalid characters"); 29 | } 30 | }); 31 | 32 | test.run(); 33 | -------------------------------------------------------------------------------- /example-ts/index.svelte: -------------------------------------------------------------------------------- 1 | 22 | 23 | 34 | 35 |
36 | 38 | 39 |
40 | 41 |
42 | 43 | 44 | 45 | {counter.value} 46 |

{haha()}

47 |

{add(1,4)}

48 |

{JSON.stringify(jo)}

49 | 50 |
51 | -------------------------------------------------------------------------------- /example-ts/buildscript.js: -------------------------------------------------------------------------------- 1 | import fs from "fs"; 2 | import esbuild from "esbuild"; 3 | import esbuildSvelte from "esbuild-svelte"; 4 | import { sveltePreprocess } from "svelte-preprocess"; 5 | 6 | //make sure the directoy exists before stuff gets put into it 7 | if (!fs.existsSync("./dist/")) { 8 | fs.mkdirSync("./dist/"); 9 | } 10 | esbuild 11 | .build({ 12 | entryPoints: [`./entry.ts`], 13 | bundle: true, 14 | outdir: `./dist`, 15 | mainFields: ["svelte", "browser", "module", "main"], 16 | conditions: ["svelte", "browser"], 17 | // logLevel: `info`, 18 | minify: false, //so the resulting code is easier to understand 19 | sourcemap: "inline", 20 | splitting: true, 21 | write: true, 22 | format: `esm`, 23 | plugins: [ 24 | esbuildSvelte({ 25 | preprocess: sveltePreprocess(), 26 | }), 27 | ], 28 | }) 29 | .catch((error, location) => { 30 | console.warn(`Errors: `, error, location); 31 | process.exit(1); 32 | }); 33 | 34 | //use a basic html file to test with 35 | fs.copyFileSync("./index.html", "./dist/index.html"); 36 | 37 | // maybe incorporate svelte-check or tsc too? 38 | // https://github.com/EMH333/esbuild-svelte/blob/main/build.js 39 | -------------------------------------------------------------------------------- /test/fixtures/ts-module-minification/module.svelte.ts: -------------------------------------------------------------------------------- 1 | export const a1 = 1; 2 | export const a2 = 1; 3 | export const a3 = 1; 4 | export const a4 = 1; 5 | export const a5 = 1; 6 | export const a6 = 1; 7 | export const a7 = 1; 8 | export const a8 = 1; 9 | export const a9 = 1; 10 | export const a10 = 1; 11 | export const a11 = 1; 12 | export const a12 = 1; 13 | export const a13 = 1; 14 | export const a14 = 1; 15 | export const a15 = 1; 16 | export const a16 = 1; 17 | export const a17 = 1; 18 | export const a18 = 1; 19 | export const a19 = 1; 20 | export const a20 = 1; 21 | export const a21 = 1; 22 | export const a22 = 1; 23 | export const a23 = 1; 24 | export const a24 = 1; 25 | export const a25 = 1; 26 | export const a26 = 1; 27 | export const a27 = 1; 28 | export const a28 = 1; 29 | export const a29 = 1; 30 | export const a30 = 1; 31 | export const a31 = 1; 32 | export const a32 = 1; 33 | export const a33 = 1; 34 | export const a34 = 1; 35 | export const a35 = 1; 36 | export const a36 = 1; 37 | export const a37 = 1; 38 | export const a38 = 1; 39 | export const a39 = 1; 40 | export const a40 = 1; 41 | export const a41 = 1; 42 | export const a42 = 1; 43 | export const a43 = 1; 44 | export const a44 = 1; 45 | export const a45 = 1; 46 | export const a46 = 1; 47 | export const a47 = 1; 48 | export const a48 = 1; 49 | export const a49 = 1; 50 | export const a50 = 1; 51 | export const a51 = 1; 52 | export const a52 = 1; 53 | export const a53 = 1; 54 | export const a54 = 1; 55 | -------------------------------------------------------------------------------- /dist/index.d.ts: -------------------------------------------------------------------------------- 1 | import type { CompileOptions, ModuleCompileOptions, CompileResult } from "svelte/compiler"; 2 | import type { PreprocessorGroup } from "svelte/compiler"; 3 | import type { Plugin, TransformOptions } from "esbuild"; 4 | type Warning = CompileResult["warnings"][number]; 5 | interface esbuildSvelteOptions { 6 | /** 7 | * Svelte compiler options 8 | */ 9 | compilerOptions?: CompileOptions; 10 | /** 11 | * Svelte compiler options for module files (*.svelte.js and *.svelte.ts) 12 | */ 13 | moduleCompilerOptions?: ModuleCompileOptions; 14 | /** 15 | * esbuild transform options for ts module files (.svelte.ts) 16 | */ 17 | esbuildTsTransformOptions?: TransformOptions; 18 | /** 19 | * The preprocessor(s) to run the Svelte code through before compiling 20 | */ 21 | preprocess?: PreprocessorGroup | PreprocessorGroup[]; 22 | /** 23 | * Attempts to cache compiled files if the mtime of the file hasn't changed since last run. 24 | * 25 | */ 26 | cache?: boolean; 27 | /** 28 | * The regex filter to use when filtering files to compile. 29 | * 30 | * Defaults to `/\.svelte(\.ts|\.js)?$/` 31 | */ 32 | include?: RegExp; 33 | /** 34 | * A function to filter out warnings 35 | * Defaults to a constant function that returns `true` 36 | */ 37 | filterWarnings?: (warning: Warning) => boolean; 38 | } 39 | export default function sveltePlugin(options?: esbuildSvelteOptions): Plugin; 40 | export {}; 41 | -------------------------------------------------------------------------------- /test/versionTests/test.js: -------------------------------------------------------------------------------- 1 | import { existsSync, mkdirSync } from "fs"; 2 | import { build } from "esbuild"; 3 | import sveltePlugin from "./index.mjs"; 4 | 5 | const esbuildVersion = process.argv[2]; 6 | const svelteVersion = process.argv[3]; 7 | 8 | //make sure the directoy exists before stuff gets put into it 9 | if (!existsSync("./dist/")) { 10 | mkdirSync("./dist/"); 11 | } 12 | 13 | //build the application 14 | build({ 15 | entryPoints: [Number(svelteVersion.at(0)) >= 5 ? "./entry5.js" : "./entry.js"], 16 | mainFields: ["svelte", "browser", "module", "main"], 17 | conditions: ["svelte", "browser"], 18 | target: "es2016", 19 | outdir: "./dist", 20 | format: "esm", 21 | logLevel: "info", 22 | minify: false, //so the resulting code is easier to understand 23 | bundle: true, 24 | splitting: true, 25 | sourcemap: "external", 26 | plugins: [sveltePlugin()], 27 | }) 28 | .then((results) => { 29 | if (results.warnings.length > 0) { 30 | console.error( 31 | "Build had warnings with esbuild version " + 32 | esbuildVersion + 33 | " and svelte version " + 34 | svelteVersion, 35 | ); 36 | process.exit(1); 37 | } 38 | }) 39 | .catch((err) => { 40 | console.error(err); 41 | console.error( 42 | "Build failed with esbuild version " + 43 | esbuildVersion + 44 | " and svelte version " + 45 | svelteVersion, 46 | ); 47 | process.exit(1); 48 | }); 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "esbuild-svelte", 3 | "version": "0.9.4", 4 | "description": "esbuild plugin to resolve .svelte files", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/EMH333/esbuild-svelte.git" 8 | }, 9 | "module": "dist/index.mjs", 10 | "main": "dist/index.js", 11 | "types": "dist/index.d.ts", 12 | "files": [ 13 | "/dist", 14 | "/CHANGELOG.md" 15 | ], 16 | "scripts": { 17 | "prepublishOnly": "git push origin --follow-tags", 18 | "postversion": "npm publish", 19 | "preversion": "npm run lint && npm run build && npm test && npm run test:compatibility", 20 | "pretest": "tsc -p tsconfig.json --noEmit", 21 | "test": "uvu test/ .*\\.mjs", 22 | "test:compatibility": "npm run build && test/versionTests/versionTests.sh", 23 | "build": "node build.js", 24 | "lint": "prettier --check --cache .", 25 | "fix": "prettier --write --cache ." 26 | }, 27 | "keywords": [ 28 | "svelte", 29 | "esbuild", 30 | "plugin" 31 | ], 32 | "author": { 33 | "name": "Ethan Hampton", 34 | "url": "https://www.ethohampton.com" 35 | }, 36 | "license": "MIT", 37 | "peerDependencies": { 38 | "esbuild": ">=0.17.0", 39 | "svelte": ">=4.2.1 <6" 40 | }, 41 | "devDependencies": { 42 | "@types/node": "^18.15.3", 43 | "esbuild": "^0.27.0", 44 | "prettier": "^3.7.0", 45 | "rewrite-imports": "^3.0.0", 46 | "sass": "^1.94.2", 47 | "svelte": "^5.33.1", 48 | "svelte-preprocess-esbuild": "^3.0.0", 49 | "typescript": "^5.5.2", 50 | "uvu": "^0.5.6" 51 | }, 52 | "engines": { 53 | "node": ">=18" 54 | }, 55 | "dependencies": { 56 | "@jridgewell/trace-mapping": "^0.3.19" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /test/errors.mjs: -------------------------------------------------------------------------------- 1 | import { test } from "uvu"; 2 | import * as assert from "uvu/assert"; 3 | import { build as _build } from "esbuild"; 4 | import { typescript } from "svelte-preprocess-esbuild"; 5 | import sveltePlugin from "../dist/index.mjs"; 6 | 7 | test("Errors (with preprocessors) are in the right spot", async () => { 8 | try { 9 | await _build({ 10 | entryPoints: ["./test/fixtures/errors/entry.js"], 11 | outdir: "../example/dist", 12 | bundle: true, 13 | write: false, //Don't write anywhere 14 | sourcemap: true, 15 | plugins: [ 16 | sveltePlugin({ 17 | preprocess: [typescript()], 18 | compilerOptions: { dev: true }, 19 | }), 20 | ], 21 | logLevel: "silent", 22 | }); 23 | } catch (e) { 24 | assert.equal(e.errors.length, 1, "Should have one error"); 25 | assert.equal(e.warnings.length, 0, "Should not have warnings"); 26 | 27 | const error = e.errors[0]; 28 | 29 | assert.equal( 30 | error.location.file, 31 | "test/fixtures/errors/error.svelte", 32 | "Should have the right file", 33 | ); 34 | assert.equal(error.location.line, 12, "Should have the right line"); 35 | assert.equal(error.location.column, 31, "Should have the right column"); 36 | assert.match( 37 | error.text, 38 | /Expected (value for the attribute|attribute value)/, 39 | "Should have the right error message", 40 | ); 41 | return; 42 | } 43 | 44 | assert.unreachable("Should have thrown an error"); 45 | }); 46 | 47 | test.run(); 48 | -------------------------------------------------------------------------------- /test/sourcemapsTest.mjs: -------------------------------------------------------------------------------- 1 | import { test } from "uvu"; 2 | import * as assert from "uvu/assert"; 3 | import { relative } from "path"; 4 | import { build } from "esbuild"; 5 | import { typescript } from "svelte-preprocess-esbuild"; 6 | import { sass } from "./utils/scss-preprocess.mjs"; 7 | import sveltePlugin from "../dist/index.mjs"; 8 | import commonOptions from "./utils/commonOptions.js"; 9 | 10 | test("Preprocessor Sourcemap test", async () => { 11 | const result = await build({ 12 | ...commonOptions, 13 | entryPoints: ["./test/fixtures/preprocessing-sourcemaps/pp-sourcemaps.js"], 14 | outdir: "../example/dist", 15 | sourcemap: "external", 16 | outdir: "out", 17 | plugins: [sveltePlugin({ preprocess: [{ style: sass() }, typescript()] })], 18 | logLevel: "silent", 19 | }); 20 | 21 | assert.equal(result.warnings.length, 1, "Should one warning"); // because of warnings tests 22 | assert.equal(result.errors.length, 0, "Should not have errors"); 23 | 24 | assert.equal(result.outputFiles.length, 4); 25 | 26 | for (let out of result.outputFiles) { 27 | if (relative(process.cwd(), out.path) === "out/pp-sourcemaps.js.map") { 28 | const json = JSON.parse(out.text); 29 | 30 | //console.log(out.text); 31 | assert.match(out.text, /