Syed Umar AnisSvelte-LexicalUpgrading svelte-lexical to Svelte 5
Syed Umar AnisSvelte-LexicalUpgrading svelte-lexical to Svelte 5
Svelte-LexicalWeb

Upgrading svelte-lexical to Svelte 5

I have upgraded svelte-lexical to Svete 5. It was a relatively smooth process considering the significant change of syntax.

Here is the story of the upgrade:

1- Run the migration utility

The Svelte team has created a migration utility to upgrade to Svelte 5. It must be executed on each project separately (it doesn’t work across monorepo). Let’s start by migrating all the projects.

pnpm dlx sv migrate svelte-5

2- Install packages

Install packages after the migration utility has made the necessary changes:

pnpm i

3- Launch the project

pn dev

I encountered an error regarding enum not being supported.

[plugin:vite-plugin-svelte] src/lib/components/toolbar/FontSizeEntry.svelte:15:2 TypeScript language features like enums are not natively supported, and their use is generally discouraged. Outside of `<script>` tags, these features are not supported. For use within `<script>` tags, you will need to use a preprocessor to convert it to JavaScript before it gets passed to the Svelte compiler. If you are using `vitePreprocess`, make sure to specifically enable preprocessing script tags (`vitePreprocess({ script: true })`)
https://svelte.dev/e/typescript_invalid_feature

The error message provided clear instructions on how to fix this one. I enabled script tags preprocessing by vite in svelte.config.js.

4- New Svelte Component Type

Next, I encountered an error about the SvelteComponent type not found. The migration guide (https://svelte.dev/docs/svelte/v5-migration-guide) indicates that SvelteComponent is deprecated and Component should be used instead.

I replaced all references to SvelteComponent type with Component.

The app now launches without any crashes, but not all functionality works yet, and numerous linting errors exist.

5- The latest Svelte package

The migration tool upgraded the svelte version to 5.0.0. It makes sense to fetch the latest version of Svelte and related packages so that I get all the fixes.

The following packages are updated:

"svelte": "^5.10.1",
"svelte-check": "^4.1.1",
"@sveltejs/adapter-auto": "^3.3.1",
"@sveltejs/kit": "^2.10.1",
"@sveltejs/package": "^2.3.7",
"@sveltejs/vite-plugin-svelte": "^4.0.2",

6- Upgrade ESLint

ESLint is complaining about runes ($state, $props). Let’s upgrade ESLint to the latest version. It resolved the issue, took a bit of effort though. This is because the ESLint config file format has changed in version 9 and I have to convert my config to the new format.

The new flat config file is called eslint.config.js. It combines both .eslintrc.cjs and .eslintignore.

The following packages are upgraded:

"eslint": "^9.16.0",
"typescript-eslint": "^8.18.1",
"eslint-plugin-import": "^2.31.0",
"@eslint/compat": "^1.2.4",
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.17.0",
"globals": "^15.14.0",

And the following should be removed:

"@typescript-eslint/eslint-plugin": "^8.18.0",
"@typescript-eslint/parser": "^8.18.0",

7- Svelte Check

I have run Svelte Check and getting 62 errors and 4 warnings. 

Let’s resolve them one by one.

8- Components are no longer classes

One of the issues is components cannot be created with new keyword as they are not classes anymore.

The migration guide explains it well here (https://svelte.dev/docs/svelte/v5-migration-guide#Components-are-no-longer-classes).

I have used createClassComponent to have compatibility with Svelte 4.

9- Using the new Component API

For a text editor, creating components on the fly is part of the core functionality. I don’t want to keep using the legacy createClassComponent API in this part of the library. Let’s try replacing it with the new mount API. 

It is easy to adopt the new API for component creation as documented here. But I am also using component.$set to update the properties of the components that is not available in Svelte 5. I have refactored the code to use the Runes approach. Essentially, it involves updating the properties that were originally passed to the component (See migration guide for details).

Successfully replaced the legacy createClassComponent with the new mount and runes API.

10- Event Bubbler

The event bubbler code injected by the migration utility is not working for me. Getting rid of the legacy event bubbler introduced, instead using onclick and other events as Component properties. This streamlines code and improves readability. 

After the last step, the app seems to be fully functional without any errors. Yay!

11- Unit Tests

Unit tests are not working. It is because my Vitest version doesn’t understand the new Svelte Component type. Upgrading Vitest to the latest version resolves the issue.

Following packages are upgraded:

"@testing-library/jest-dom": "^6.6.3",
"@testing-library/svelte": "^5.2.6",
"@vitest/ui": "^2.1.8",
"jsdom": "^25.0.1",
"vitest": "^2.1.8"

12- Use Runes Mode

I could see some of the components are in legacy mode, they don’t need to be.

We can force them into Runes mode by inserting the following directive at the top of the file.

<svelte:options runes={true} />

13- TS Type Errors

Fix all TypeScript type definition errors introduced during migration to Svelte 5. These are easy to fix.

14- Accessibility Warnings

Fix the new accessibility warnings. In my case, these are mostly about defining aria-label on buttons and removing ignore comments that are not applicable anymore.

15- Code Formatting

Fix formatting issues introduced during migration. Pretty straightforward.

16- Run Tests

Rest of the errors were pretty minor ones and easy to fix. With all svelte-check, ESLint and Prettier errors fixed, let’s execute the tests. 

All 284 tests are passing 🙂

Kudos to the Svelte team for making such a major migration so easy. This must have required a lot of hard work.

Hi, I’m Umar

Leave a Reply

Your email address will not be published. Required fields are marked *