Add a Svelte Project
The code for this example is available on Github:
Example repository/nrwl/nx-recipes/tree/main/svelte
Supported Features
Because we are not using a Nx plugin for Svelte, there are a few items we'll have to configure manually. We'll have to configure our own build system. There are no pre-created Svelte-specific code generators. And we'll have to take care of updating any framework dependencies as needed.
✅ Run Tasks ✅ Cache Task Results ✅ Share Your Cache ✅ Explore the Graph ✅ Distribute Task Execution ✅ Integrate with Editors ✅ Automate Updating Nx ✅ Enforce Module Boundaries 🚫 Use Task Executors 🚫 Use Code Generators 🚫 Automate Updating Framework Dependencies
Setup workspace
Create a new Nx workspace
❯
create-nx-workspace@latest acme --preset=ts-standalone --nx-cloud=true
Add @nx/vite, svelte, and other dependencies to your workspace
❯
npm install --save-dev @nx/vite @nx/js vitest vite svelte svelte-check @sveltejs/vite-plugin-svelte
Create the application
❯
touch index.html
And add the following content:
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Acme</title>
  </head>
  <body>
    <div id="app"></div>
    <script type="module" src="./src/main.ts"></script>
  </body>
</html>
Navigate to src/index.ts and change it to src/main.ts and add the following content:
import App from './App.svelte';
const app = new App({
  target: document.getElementById('app'),
});
export default app;
Create a new file src/App.svelte and add the following content:
<script lang="ts">
    let count: number = 0
    const increment = () => {
      count += 1
    }
  </script>
  <button on:click={increment}>
    count is {count}
  </button>
Configure Nx to build and serve the application
Navigate to vite.config.ts update the file name to vite.config.mts and add the following content:
// Add this to your imports
import { svelte } from '@sveltejs/vite-plugin-svelte';
export default defineConfig({
  plugins: [
    //...
    svelte(),
  ],
  server: {
    port: 4200,
    host: 'localhost',
  },
});
We change vite.config.ts to vite.config.mts because '@sveltejs/vite-plugin-svelte' is an ESM only package. As a result, we need to use the .mts extension to tell Nx to use the ESM loader. See more here: ESM Package
Update your tsconfig.lib.json to be tsconfig.app.json and add the following content:
{
  "extends": "./tsconfig.json",
  "compilerOptions": {
    "moduleResolution": "node",
    "target": "esnext",
    "ignoreDeprecations": "5.0",
    "isolatedModules": true,
    "sourceMap": true,
    "types": ["svelte", "node", "vite/client"],
    "strict": false,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "checkJs": true
  },
  "include": [
    "src/**/*.d.ts",
    "src/**/*.ts",
    "src/**/*.js",
    "src/**/*.svelte",
    "vite.config.mts"
  ],
  "exclude": ["jest.config.ts", "src/**/*.spec.ts", "src/**/*.test.ts"]
}
Navigate to project.json and update it with the following content:
    "build": {
      "executor": "@nx/vite:build",
      "outputs": ["{options.outputPath}"],
      "defaultConfiguration": "production",
      "options": {
        "outputPath": "dist/acme"
      },
      "configurations": {
        "development": {
          "mode": "development"
        },
        "production": {
          "mode": "production"
        }
      }
    },
    "serve": {
      "executor": "@nx/vite:dev-server",
      "defaultConfiguration": "development",
      "options": {
        "buildTarget": "acme:build"
      },
      "configurations": {
        "development": {
          "buildTarget": "acme:build:development",
          "hmr": true
        },
        "production": {
          "buildTarget": "acme:build:production",
          "hmr": false
        }
      }
    },
This allows us to use nx build and nx serve to build and serve or Svelte application.
Test it out
Build the application
❯
nx build acme
Your build artifacts should be in dist/acme
Serve the application
❯
nx serve acme
Navigate to http://localhost:4200 and you should see your application.
Create a library
Instead of having our Counter directly defined in App.svelte file, let's create a library that we can import into our application.
❯
nx generate @nx/js:library --name=Counter --unitTestRunner=vitest --bundler=vite --importPath=@acme/counter
Create the Counter component at counter/src/lib/Counter.svelte and copy the contents of your src/App.svelte file into it.
Update your libs/counter/src/lib/index.ts to export your Counter component.
export { default as Counter } from './Counter.svelte';
The default is very import here as it allows us to import the component using import { Counter } from '@acme/counter' instead of import Counter from '@acme/counter'.
Update your root ./vite.config.mts to include the following:
export default defineConfig({
  //... other config
  resolve: {
    alias: {
      '@acme/counter': fileURLToPath(
        new URL('./counter/src/index.ts', import.meta.url)
      ),
    },
  },
});
This allows the runtime to resolve the @acme/counter import to the correct location.
Finally update your src/App.svelte to use the counter component.
<script lang="ts">
  import { Counter } from '@acme/counter';
</script>
<Counter />
Now we can build and serve our application again.
❯
nx build acme
To generate the build artifact at dist/acme.
❯
nx serve acme
To serve the application at http://localhost:4200.
More Documentation
A larger example including libraries, test and more is available at Nx Svelte Example on Github.