NSWI153: Advanced Web Applications

JavaScript : Project

Preliminaries

Please read this section at least one day prior to the seminar. This section outlines what you are expected to know, be able to do, or prepare in advance. Following these instructions will help you get the most out of the seminar and ensure smooth participation.

Preliminaries : Knowledge, Skills, and Competence


Before the start of the practical, you should be able to:

  • Create a simple website using HTML, CSS, and JavaScript.
  • Make sure you watched recording from "Simplified JavaScript eco-system" lecture.

Preliminaries : Using your own computer


This slide applies to you only if you plan to use your own computer for the practical.

Before the start of the practical, make sure that:

  • You have Node.js installed.
  • You can run npm, Node.js package manager, from a command line using following command:
    
              npm create vite@latest
            

Objectives

  • Node.js, npm, Vite
  • HTML, JavaScript, SASS, Typescript
  • Multiple entry points
  • Configuration
  • Code quality, Prettier, ESLint
  • Hot Redeployment
  • Deployment

Demonstration: Vite 1 / 2

Vite is a blazing fast frontend build tool powering the next generation of web applications.

Our first project

Vite is a (zero-configuration) build tool. It is opinionated and comes with sensible defaults out of the box. Vite can be installed using npm. npm is distributed with Node.js. We employ vite to create a new project using "npm create" command, which is similar to "composer create-project" command.


      npm create vite@latest
    

Select Vanilla as a framework and TypeScript variant. Take a look at:

  • package.json
  • index.html
  • rename "style.css" to "style.scss"
  • npm run dev
  • hot redeployment
  • npm run build

Take a look at file names in "dist" directory. Why are there some "random" suffixes for css and js files?

Typescript

TypeScript is a strongly typed programming language that builds on JavaScript, giving you better tooling at any scale.

Using Typescript

Set initial counter value to "0" in counter.ts file.


      setCounter("0");
    

What should happen and what happened?

Assignment : Articles

Create a new entry point "articles.html", a new main TypeScript file "articles-main.ts" and a service file "articles-service.ts". Include "articles-main.ts" from "articles.html". Create article service, return mocked article list, and implement renderer.

// articles-main.ts
import { fetchArticles } from './articles-service.ts'

async function renderArticles() {
  const articles = await fetchArticles();
  /* TODO: Render articles */
}

renderArticles()
    
// articles-service.ts
interface Article {  identifier: string;  title: string;  }

export async function fetchArticles(): Promise<Article[]> {
  /* TODO */
}
    

Continue to the next slide once you are done >>>

Debriefing

...

Congratulations, if you have followed the instructions, you have just reached the end of this exercise.

Vite 2 / 2

Multiple entry points

Unless developing single-page-application we may need multiple entry files. It works just fine for "dev", but same is not true for "build".

Build tools often provide tool-specific way of configuration. In case of Vite, we can employ vite.config.js file to configure multiple entry points.


      // vite.config.js
      import { resolve } from 'path'
      import { defineConfig } from 'vite'

      export default defineConfig({
        build: {
        rollupOptions: {
          input: {
            main: resolve(__dirname, 'index.html'),
            articles: resolve(__dirname, 'articles.html'),
          },
        },
      }});
    

Configuration

Semi-random configuration classification:

  • Build / Compile time
  • Deployment
  • ...

We can provide the configuration using a configuration file, like JSON or YAML file. We can also utilize environment variables. We can also employ version of .env file.

In general, configuration files do not belong into a versioning system.

Configuration and Vite

Vite supports .env files and environment variables out of the box. Selected variables:

  • import.meta.env.BASE_URL
  • import.meta.env.PROD
To prevent accidentally leaking env variables to the client, only variables prefixed with VITE_ are exposed to your Vite-processed code

Introduce .env file with "VITE_LIST_OWNER" variable and use it in the "article-main.ts" file as a prefix to the article list.

Code quality

What, why, how?

Code quality and JavaScript

We utilize Prettier to take care of code formatting. While Prettier works with multiple source types, including PHP, we utilize it only in scope of Vite project. It may be useful to consider IDE integration.

Another step is to utilize ESLint which statically analyzes the code.

While it is possible to run both tools using npx, we integrate both tools into our Vite project.

Prettier


      npm install --save-dev prettier
    

We can employ prettier.config.ts file to customize Prettier's options. Note that we can use different files to configure Prettier. You can execute prettier manually using:


      npx prettier -w .
    

ESLint

ESLint can be executed on demand or during the development to provide instantaneous feedback. Besides ESLint we also need plugins, for different languages, and configurations. We utilize ESLint and typescript-eslint.


      npm install -D eslint @eslint/js
      # Integration with Typescript
      npm install -D typescript typescript-eslint
      # Integration with Prettier
      npm install -D prettier eslint-plugin-prettier eslint-config-prettier
      # Global identifiers from different JavaScript environments
      npm install -D globals
    

ESLint utilizes eslint.config.mjs, or other file depending on your setup, for configuration and .eslintignore to ignore directories. Alternatives are JSON file, YAML file, part of package.json, eslint.config files, etc.. We use "eslint.config.mjs" file, see following slide.

Add following line to script section in your package.json file to execute ESLint in current directory.


      "lint": "eslint . --fix"
    

Configuring ESLint


      // eslint.config.mjs
      import eslint from "@eslint/js"
      import globals from "globals"
      import tseslint from "typescript-eslint"
      import { defineConfig } from "eslint/config"
      // https://github.com/prettier/eslint-plugin-prettier
      import prettier from "eslint-plugin-prettier/recommended"

      export default defineConfig([
        {
          // This is a special construct and must be in a separate section.
          // https://github.com/eslint/eslint/discussions/18304
          ignores: ["**/dist/*"],
        },
        eslint.configs.recommended,
        tseslint.configs.recommended,
        {
          languageOptions: {
            globals: {
              ...globals.browser,
              ...globals.node,
            },
          },
        },
        prettier,
      ]);
    

Hot Redeployment

You may also know it as "hot deployment", "hot reloading", "hot swapping".


Hot deployment is the process of adding new components (such as WAR files, EJB Jar files, enterprise Java beans, servlets, and JSP files) to a running server without having to stop the application server process and start it again.

Hot Redeployment with Vite

Hot Module Replacement (HMR) is capable of replacing JS code without the need of a reload. You can integrate with HRM using build tool API, e.g. Vite's API. This integration is usually handled by a framework, but we can interact with it as well. It works on level of modules ~ individual files ~ HMR boundary.

  • Try to add console.log statements and observe the reload.
  • Create counter service in service.ts.
  • Add support for reload to consuming module.

      // service.ts
      export const createService = () => {
        return {
          data: { counter: 0 },
          value() { return this.data.counter },
          increase() { this.data.counter += 1 }
        }
      }
    

Hot Redeployment 1 / 2

Create "hmr-main.ts" as a copy of "main.ts", just to keep the original file around. Next use the new service in "main.ts".


      import { createService } from "./service";
      // ...
      let service = createService();
      const setupCounter = (element: HTMLButtonElement) => {
        element.innerHTML = 'count is 0';
        element!.addEventListener("click", () => {
          service.increase();
          element.innerHTML = `count is ${service.data.counter}`;
        });
      };
    

Do not forget to remove the original import of "setupCounter" function.

Hot Redeployment 2 / 2

We need custom implementation of module reloading.


      if (import.meta.hot) {
        import.meta.hot.accept(["./service"], ([serviceModule]) => {
          // Get next service.
          const nextService = serviceModule.createService();
          // Move data from old to new.
          nextService.data = service.data;
          // Replace old with new.
          service = nextService;
        })
      }
    

Hot Redeployment : Resources

Proxy to API

Vite has build in server proxy. You can use it to proxy local endpoint to anything.

Works best when combined with Environment Variables in Config.

Demonstration: Deployment

I appreciate the opportunity (/obligation) to deploy my own application - I believe that many people have never tried it before. But why php? :( I don't know and can't use php - so most of the time I just struggle with the syntax and in the end I end up throwing it to Claude...

Anonymous 2026

Deployment with Vite

Run "build" command and check the output, the "./dist" directory. Would it work when deployed to you home directory at webik?

It is possible to use configuration (variables) in the vite.config.js.

Semestral / Team project

  1. Form a team of 3-4 people.
  2. Select a team leader.
  3. The team leader sends me list of team members.
  4. You get repository where to develop your project.

PS: There is no assignment from this practical.

Questions, ideas, or any other feedback?

Please feel free to use the anonymous feedback form.