Get away from jQuery to Svelte, no pain

Hello everyone.

I’m a backend developer and I solve the front-end tasks as I can, that is, on jQuery, it worked in 2015, it works now. But with Vue and React, this is no longer a camphile. Out of love for a special way, I decided to master Angular / React / Vue, which has not been tested by millions of developers, I decided to try Svelte .

Having done a couple of exercises from the textbook, I decided to move on to practice. For this, I took one of my successfully completed test tasks.

On assignment it was necessary to make a review of the list of tasks and one task from this list, CRUD is not needed.

The client part is implemented as a SPA, and all work with the DOM is done through jQuery, it is an excellent candidate to replace jQuery with Svelte.

Below I will talk about the very first obstacles along the way and of course about how to overcome them.
The Svelte tutorial is very accessible and intuitive, but how to embed Svelte in an arbitrary project is not very clear, because Svelte is not a library like jQuery, it is a compiler, that is, code written using Svelte directives must somehow be compiled into native JS.

Another stumbling block was the use of

$

in Svelte, this is a reserved character, so using it in the code that will be compiled by Svelte leads to an error:


[!] (plugin svelte) ValidationError: $ is an illegal variable name

Using `$`


Of course, the question may arise: what is `$` like if we completely change jQuery to Svelte?
Yes, the question is reasonable, but if you think about it, the problem will become clear - you don’t need to eat the whole elephant, experienced people eat the elephant in parts. In terms of the transition from using jQuery to using Svelte, it will be a series of atomic refactoring, progress will always be visible and the “system” as a whole will always be in working condition.

The plan is this: rewrite a piece, test, repair, rewrite the next piece, and so on until we eat the whole elephant without a trace.

The problem with `$` occurs only in the code that Svelte compiles, I have all the SPA logic moved to the “business-process.js” file, there is no need to solve this problem, but all the code from “business-process.js” should go to App.svelte and other related application components.

After the first refactoring, App.svelte appeared with the following code:


<script>
    jQuery(function ($) {

        function loadStartScreen() {
        loadPaging(0, settings.capacity);
        loadPage(0, settings.capacity);
        }

        loadStartScreen();

        async function search(sample) {
            $('#paging').empty();
            $.ajax({
                type: "GET",
                url: `/api/v1/task/search/${sample}/`,
                dataType: "json",
                success: renderTasks,
                error: function (jqXHR, textStatus, errorThrown) {
                },
                timeout: 500,
            });
        }

        $("#search").submit(async function (event) {
            event.preventDefault();
            const sample = $("#sample").val();

            if (sample) {
                search(sample);
            }
            if (!sample) {
                loadStartScreen();
            }
        });
    });
</script>

<div class="container">
    <h1>  </h1>

    <form class="form-horizontal" id="search">
        <div class="form-group">
            <label class="control-label col-sm-2" for="sample">
            
            </label>
            <div class="col-sm-10">
                <input id="sample" class="form-control " type="search"
                 placeholder="  " 
                 autofocus autocomplete="on" />
            </div>
        </div>
    </form>
    <div id="taskList">
    </div>
    <div id="paging">
    </div>

The code is working, actually Svelte is not yet used at all, at this stage Svelte only generates HTML code that is inserted into

<body>

The variable `$` is isolated in the call

jQuery(function ($) {});

no naming conflict.

We bind the sample variable with the value of the input element with id = "sample":


                <input id="sample" class="form-control " type="search"
                 placeholder="  "
                 autofocus autocomplete="on"
                 bind:value={sample}
                 />

On the submit event of the form element with id = "search", the code is executed:


        $("#search").submit(async function (event) {
            event.preventDefault();

            if (sample) {
                search(sample);
            }
            if (!sample) {
                loadStartScreen();
            }
        });

This code must be executed according to the Svelte directive, we rewrite it:


<script>
    async function svelteSearch(event) {
        event.preventDefault();
        if (sample) {
            search(sample);
        }
        if (!sample) {
            loadStartScreen();
        }
    }
</script>
<form class="form-horizontal" id="search"
on:submit="{svelteSearch}">
</form>

The code compiles, but does not work, because the search () function is defined in the jQuery scope (function ($) {}); and in the global scope this function is not visible. Pull search () into one scope with svelteSearch (event):


<script>
    function loadStartScreen() {
        loadPaging(0, settings.capacity);
        loadPage(0, settings.capacity);
    }

    let sample = '';

    jQuery(function ($) {
        loadStartScreen();
    });
    async function search(sample) {
        $('#paging').empty();
        $.ajax({
            type: "GET",
            url: `/api/v1/task/search/${sample}/`,
            dataType: "json",
            success: renderTasks,
            error: function (jqXHR, textStatus, errorThrown) {
            },
            timeout: 500,
        });
    }
    async function svelteSearch(event) {
        event.preventDefault();
        if (sample) {
            search(sample);
        }
        if (!sample) {
            loadStartScreen();
        }
    }
</script>

Such code does not compile:


[!] (plugin svelte) ValidationError: $ is an illegal variable name

What to do? Google it! “Svelte how to import jquery”: How do I use jQuery in Svelte
I didn’t like the answer marked as “correct” to import a third-party library (arbitrary * .js), it’s not enough to write import *, you have to register it in rollup.config.js external:


export default { external []};

The second option with window. $ Requires much less body movements and since we plan to completely abandon the use of jQuery, this directive for import will be temporary and familiarity with import can be postponed until later.

Use copy-paste with stack overflow:


<script>
    function loadStartScreen() {
        loadPaging(0, settings.capacity);
        loadPage(0, settings.capacity);
    }
    jQuery(function ($) {
        loadStartScreen();
    });

    let sample = '';

    async function search(sample) {
        window.$('#paging').empty();
        window.$.ajax({
            type: "GET",
            url: `/api/v1/task/search/${sample}/`,
            dataType: "json",
            success: renderTasks,
            error: function (jqXHR, textStatus, errorThrown) {
            },
            timeout: 500,
        });
    }
    async function svelteSearch(event) {
        event.preventDefault();
        if (sample) {
            search(sample);
        }
        if (!sample) {
            loadStartScreen();
        }
    }
</script>

<div class="container">
    <h1>  </h1>
    <form class="form-horizontal" id="search"
    on:submit="{svelteSearch}">
        <div class="form-group">
            <label class="control-label col-sm-2" for="sample">
            
            </label>
            <div class="col-sm-10">
                <input id="sample" class="form-control " type="search"
                 placeholder="  "
                 autofocus autocomplete="on"
                 bind:value={sample}
                 />
            </div>
        </div>
    </form>
// ..skip..
</div>

It remains to get rid of:


    jQuery(function ($) {
        loadStartScreen();
    });

We remove this code and add it to the markup:


<svelte:window on:load = {loadStartScreen} />

Done.

In the Svelte documentation , you can find:
<svelte: document>
The <svelte: document> tag, just like <svelte: window>, gives you a convenient way to declaratively add event listeners to the document object. This is useful for listening to events that don't fire on window, such as mouseenter and mouseleave.

In practice, we have:


[!] (plugin svelte) ParseError: Valid <svelte:...> tag names are svelte:head, svelte:options, svelte:window, svelte:body, svelte:self or svelte:component

That is, the tag was cut out of the code , but they forgot to delete it from the documentation, to my amazement, Svelte is developed not by the gods, but by people who also tend to leave something for later and forget.

How to integrate jQuery in Svelte code with little blood I told.

How to compile Svelte directives in JS code


We pump an empty project into a separate folder as described in the Svelte blog (install Node.js along the way). Now we transfer the downloaded files to the directory of our project.

We transfer the files from “public” to where we have the files to be downloaded by the client (the user's browser), I have it “public / assets / Site”, I do not need styles from “global.css”, I did not transfer this file.

The file "public / index.html", I transferred to where the server will take the template for view: "view / Site / index.html".

Files from "src" are added to the source of the frontend - "src / frontend".

Files describing the sources of the frontend:

  • rollup.config.js
  • package-lock.json
  • package.json

I shifted to the root, there the IDE picked them up and took care of everything (installed dependencies).
Now you need to change the compilation configuration of Svelte directives in JS.

Open rollup.config.js and change the file paths:


export default {
	input: 'src/frontend/main.js',
	output: {
		sourcemap: true,
		format: 'iife',
		name: 'app',
		file: 'public/assets/Site/bundle.js'
	},
	plugins: [
		svelte({
			dev: !production,
			css: css => {
				css.write('public/assets/Site/bundle.css');
			}
		}),

That's the difficulty with the initial integration of Svelte into an existing project.

We install the dependencies and start tracking changes in the source code of the frontend for compilation on the fly:

npm install
npm run dev

Do not forget


Edit the presentation template (in my case, it is "view / Site / index.html"):

  • Everything inside the body tag is portable to App.svelte
  • Add links to the necessary resource files

    
    <head>
      <link rel='stylesheet' href='/assets/Site/bundle.css'>
    </head>
    
  • After the body tag, add a “link” to the generated assembly file:

    
    <body>
    </body>
    <script src='/assets/Site/bundle.js'></script>
    


The entire code can be viewed in the repository .

The final abandonment of jQuery in this project is still a long way off, but the article was not about that, this article is about the first steps to implement Svelte in your code, about the simplest things.

Thank you for the attention.

Threat
How the transition turned out, you can read in the next article " How it was "

Source: https://habr.com/ru/post/undefined/


All Articles