9.1 KiB
Add a Svelte Project
The code for this example is available on Github:
{% github-repository url="https://github.com/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.
{% pill url="/core-features/run-tasks" %}✅ Run Tasks{% /pill %} {% pill url="/core-features/cache-task-results" %}✅ Cache Task Results{% /pill %} {% pill url="/core-features/remote-cache" %}✅ Share Your Cache{% /pill %} {% pill url="/core-features/explore-graph" %}✅ Explore the Graph{% /pill %} {% pill url="/core-features/distribute-task-execution" %}✅ Distribute Task Execution{% /pill %} {% pill url="/core-features/integrate-with-editors" %}✅ Integrate with Editors{% /pill %} {% pill url="/core-features/automate-updating-dependencies" %}✅ Automate Updating Nx{% /pill %} {% pill url="/core-features/enforce-module-boundaries" %}✅ Enforce Module Boundaries{% /pill %} {% pill url="/core-features/plugin-features/use-task-executors" %}🚫 Use Task Executors{% /pill %} {% pill url="/core-features/plugin-features/use-code-generators" %}🚫 Use Code Generators{% /pill %} {% pill url="/core-features/automate-updating-dependencies" %}🚫 Automate Updating Framework Dependencies{% /pill %}
Setup workspace
Create a new Nx workspace
{% tabs %} {%tab label="npm"%}
npx create-nx-workspace@latest workspace --preset=react-monorepo --style=css --bundler=vite --nx-cloud=true --appName=acme
{% /tab %} {%tab label="yarn"%}
npx create-nx-workspace@latest workspace --preset=react-monorepo --style=css --bundler=vite --nx-cloud=true --appName=acme --pm yarn
{% /tab %} {%tab label="pnpm"%}
npx create-nx-workspace@latest workspace --preset=react-monorepo --style=css --bundler=vite --nx-cloud=true --appName=acme --pm pnpm
{% /tab %} {% /tabs %}
Add @nx/vite, svelte, and other dependencies to your workspace
{% tabs %} {%tab label="npm"%}
npm install --save-dev @nx/vite @nx/js vitest vite svelte svelte-check @sveltejs/vite-plugin-svelte
{% /tab %} {%tab label="yarn"%}
yarn add --dev @nx/vite @nx/js vitest vite svelte svelte-check @sveltejs/vite-plugin-svelte
{% /tab %} {%tab label="pnpm"%}
pnpm add --save-dev @nx/vite @nx/js vitest vite svelte svelte-check @sveltejs/vite-plugin-svelte
{% /tab %} {% /tabs %}
Create the application
Before we start to create our application, let's remove the React application that was created for us.
rm -rf apps/acme/src/app/*
Update your apps/acme/src/index.html to the following:
<!DOCTYPE html>
<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 apps/acme/src/main.tsx and change it to apps/acme/src/main.ts and add the following content:
import App from './app/App.svelte';
const app = new App({
target: document.getElementById('app'),
});
export default app;
Create a new file apps/acme/src/app/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',
},
});
{%callout type="Note" title="Why use the .mts file extension?" %}
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
{% /callout %}
Update your tsconfig.app.json with 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:
{
"targets": {
"build": {
"executor": "@nx/vite:build",
"outputs": ["{options.outputPath}"],
"defaultConfiguration": "production",
"options": {
"outputPath": "dist/apps/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
}
}
}
}
}
We also need to add a svelte.config.js file to the project root with the following content:
import { vitePreprocess } from '@sveltejs/vite-plugin-svelte';
export default {
// Consult https://svelte.dev/docs#compile-time-svelte-preprocess
// for more information about preprocessors
preprocess: vitePreprocess(),
};
Update your package.json to include:
{
"type": "module"
}
{% callout "Note" title="Why use the type: module?" %}
We need to add "type": "module" to our package.json file because we are using ESM only packages. See more here: ESM Package
{% /callout %}
Test it out
Build the application
nx build acme
Your build artifacts should be in dist/apps/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.
{% callout type="note" title="Directory Flag Behavior Changes" %}
The command below uses the as-provided directory flag behavior, which is the default in Nx 16.8.0. If you're on an earlier version of Nx or using the derived option, omit the --directory flag. See the workspace layout documentation for more details.
{% /callout %}
nx generate @nx/js:library --name=Counter --directory=libs/counter --unitTestRunner=vitest --bundler=vite --importPath=@acme/counter
Create the Counter component at libs/counter/src/lib/Counter.svelte and copy the contents of your apps/acme/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';
{% callout "Note" title="Remember the default keyword"%}
The default is import here as due to the aliasing we'll be doing later, we'll need to import the Counter component as import { Counter } from '@acme/counter'.
{% /callout %}
Update your project's /apps/acme/vite.config.mts to include the following:
export default defineConfig({
//... other config
resolve: {
alias: {
'@acme/counter': fileURLToPath(
new URL('/libs/counter/src/index.ts', import.meta.url)
),
},
},
});
This allows the runtime to resolve the @acme/counter import to the correct location.
Finally update your apps/acme/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/apps/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.