DEV Community

Cover image for Introducing Nue JS, a Svelte alternative
Matt Angelosanto for LogRocket

Posted on • Originally published at blog.logrocket.com

Introducing Nue JS, a Svelte alternative

Written by Rahul Chhodde✏️

Nue JS is a new JavaScript framework that positions itself as a compelling and faster alternative to established frontend JavaScript tools like React, Vue, and Svelte. Although still under development, it has already started gaining attention for its innovative development approach.

Like Svelte, Nue does not use a virtual DOM and instead compiles components into highly optimized imperative code that directly manipulates the DOM. This results in faster rendering, especially for complex applications.

This article will look at Nue as an alternative to Svelte, which is a mature and established JavaScript framework for creating performant JavaScript applications. We will cover:

We’ll go through some code examples to explore Nue fully. You can check out the code on GitHub and fork the project to explore it on your own.

What is Nue JS?

Tero Piirainen, the creator of Nue as well as the component-based UI library Riot.js, was dissatisfied with the complexity and excessive bloat of modern frontend frameworks. This drove him to introduce a fresh approach emphasizing simplicity, performance, and an improved developer experience.

Nue follows a minimalist approach and aims to offer improved solutions for creating web apps and conventional websites. Without hooks, effects, and props in the traditional sense, Nue leaves it up to the developer to decide how they prefer to extend the framework to add different functionalities.

Its syntax is essentially HTML, where you can also use Nue-only variables, directives, attributes, and modifiers to change how things should be rendered.

Since the majority of the development work in Nue revolves around HTML, CSS, and JavaScript, you may not need additional expertise beyond that. This makes its learning curve shorter and helps developers quickly adapt to the framework.

Combined with the advanced features of NueKit in the future, Nue aspires to position itself as a convincing alternative to popular tools like Vite, Next.js, and Astro.

In the following sections, we will delve deeper into Nue, exploring its similarities and differences with Svelte, its advantages, and, most importantly, the basics of its syntax and a few additional technical aspects.

Similarities and differences between Nue and Svelte

When choosing a JavaScript framework for your project, it is essential to understand the similarities and differences between the options. This will help inform your decision so that you select the framework that best suits your project's requirements and goals.

While Nue and Svelte share the common goal of empowering web UI development, they also share certain fundamental characteristics, as evident from their codebases and code examples.

The below similarities also offer a glimpse into Svelte and its nature if you are not already familiar with it. Let's explore these shared traits:

  • Declarative UI construction: Both Nue and Svelte embrace a declarative approach to UI development. This means that you specify how you want your UI to appear, and the framework takes care of rendering it. This streamlined approach simplifies the creation of complex UIs without the need for excessive code
  • Unidirectional data flow: Svelte and Nue both adhere to the unidirectional data flow paradigm. This means that data flows from the model to the view but not the other way around. This unidirectional data flow enhances code comprehensibility and facilitates debugging
  • Compiler-driven code optimization: The code you write in both Nue and Svelte undergoes a transformation into WebAssembly and pure JavaScript respectively before execution. This compilation process results in significant performance enhancements, especially in scenarios involving complex UIs
  • Lightweight and speedy performance: Both frameworks prioritize lightweight and rapid operation, making them an excellent choice for developing high-performance web applications
  • Component-centric architecture: Nue and Svelte adopt a component-based architecture for structuring applications. This approach involves constructing UIs from reusable components and streamlining the development and maintenance of complex UIs
  • TypeScript-free core: Notably, both Svelte and Nue embrace a TypeScript-free core to simplify their ecosystems. They support dynamic typing within JavaScript, with Svelte utilizing JS Doc for type declarations

Meanwhile, here are some of the significant differences between Nue and Svelte summarized in a table for easier viewing:

Nue Svelte
Build size An exceptionally lightweight framework, with a minified and gzipped size of just 2.3kB. Since it’s in its early days of development, you can expect it to grow in size eventually. Impressively small, with a minified and gzipped size of 2.6kB, making it nearly as compact as Nue, even though it has been around for a few years now.
Syntax Employs a straightforward and intuitive syntax, resembling embedded HTML, CSS, and JavaScript. This approach simplifies the development process and enhances code readability. Uses a template syntax that allows you to seamlessly integrate HTML, CSS, and JavaScript directly into your components. It offers a simple yet powerful way to create dynamic and interactive interfaces.
Code compilation Compiles to WebAssembly, which makes it a bit more efficient than Svelte, utilizing a streamlined virtual DOM. Compiles to vanilla JavaScript at build time, eliminating virtual DOM overhead. It employs a distinct reactive model and offers a beginner-friendly learning curve.
Ecosystem Nue is relatively new to the scene, and its ecosystem is smaller than Svelte's. However, the Nue community is expected to expand further, and developers will eventually gain access to Nue-optimized libraries and tools tailored to their needs. Svelte has a more mature ecosystem, enriched with a wide array of libraries and tools, making it a well-established choice for various web development projects.
State management Uses a reactive state system like Svelte, but takes a more declarative approach. Instead of manually managing the state, you declare what needs tracking, letting Nue.js handle automatic UI updates. This approach offers flexibility but requires upfront planning and implementation. Uses reactive programming to manage the state, so state changes are automatically reflected in the UI without needing explicit updates. Svelte also provides a number of built-in features for managing state, such as observables and stores.
Build tools Uses Bun's native bundler by default, but gives you the flexibility to use a different or fallback bundler, such as ESBuild. We'll demonstrate this later in the article. Uses Vite for code bundling

Svelte’s minimal footprint coupled with its larger community positions it as an excellent choice for optimizing web applications. Meanwhile, Nue offers a simple, flexible development experience with the option to customize or extend its capabilities as needed.

Advantages specific to Nue JS

Nue claims to offer some advantages that are missing with other prominent JavaScript frameworks and significantly enhance frontend development scalability for the following four reasons:

  • Enhanced separation of concerns: Nue promotes a clear separation of concerns, making it easier to scale your project. Clean, easy-to-read code is more conducive to scalability than complex, tangled “spaghetti” code
  • Minimalistic approach: Nue’s minimalistic design philosophy encourages succinct code. With just a hundred lines of code, you can achieve what might require a thousand lines in other frameworks. This minimalism simplifies project management and streamlines the scaling process
  • Optimal skill alignment: Nue allows your development team to specialize effectively. With Nue’s decoupled styles, UI designers and UX developers can focus on the frontend’s visual aspects, while JavaScript and TypeScript developers can concentrate on the backend. This specialization fosters efficiency and scalability in the development process
  • Faster page loads: Nue’s decoupled styling makes isolating primary CSS from secondary elements easy, allowing you to ensure that your HTML page stays within the critical 14kB limit. This optimization results in faster page loading times

Keep in mind, though, that Nue is still being actively developed. While this means we can expect more improvements to the framework itself as well as new advancements in its ecosystem, this may also lead to occasional bugs and broken features.

Getting started with Nue JS

Nue strongly emphasizes its compatibility with Bun, a new JavaScript runtime. However, it can also be configured to work in a Node.js environment. In this section, I will lead you through the setup process of Nue on Node.js, running your first Nue app, and exploring its components basics.

Installing Nue

There is currently no Nue JS CLI available. You can install it in one of two ways. The first option is creating a new Nue project from scratch and adding the Nue JS core package. Otherwise, you can follow the recommended approach and clone the starter project provided by Nue, which includes examples.

Note that as we mentioned earlier, Nue is currently in its early development stages. Given this, it's expected to have some bugs, such as the one I encountered in version 0.1.1 where a core function requires a slight adjustment to work properly.

Let's follow the recommended approach and clone Nue’s official create-nue starter project:

git clone https://github.com/nuejs/create-nue.git
Enter fullscreen mode Exit fullscreen mode

Next, navigate to the create-nue directory and install the necessary dependencies using your preferred package manager. In this example, we'll use pnpm:

cd create-nue
pnpm install
Enter fullscreen mode Exit fullscreen mode

You should see something like the below: Developer Terminal With Yellow Arrow And Text Indicating Where Nue Js Core Is Installed The install command will ensure that all required dependencies are in place before you run your Nue project for the first time. If you are not using Bun, which provides built-in bundling, you can install esbuild to minify and bundle your files.

Running your Nue project

After installation, you can use the following command to run the Nue JS project you just obtained and installed from GitHub:

pnpm run start
Enter fullscreen mode Exit fullscreen mode

You should see the following: Developer Terminal With Yellow Arrow And Text Indicating Lines Showing Nue Js App Running On Node Server As shown in the screenshot above, esbuild is installed in the project. Since we're not using Bun, it's automatically configured as the fallback bundler for minifying the build files, as specified in the scripts/minify.js file. The folder structure will be explained in more detail in the next section.

Exploring the folder structure

When you open the installed project, you will see the folder structure as shown below:

.
└── create-nue/
    ├── node_modules
    ├── scripts
    ├── src
    ├── www
    ├── package.json
    ├── ...
    ├── ...
    └── ᠎
Enter fullscreen mode Exit fullscreen mode

It’s a bit different from Svelte and its other counterparts. The most important directories to focus on are scripts, src, and www:

  • The scripts directory contains various build scripts that automate tasks such as building, compiling, packaging, and preparing a Nue JS application for deployment
  • The src directory, as the name implies, contains all the source files, including components, layouts, and data
  • The www directory contains the final build and includes all files generated by the Nue JS core using resources from the src directory

It is important to note that the names of these directories are not strictly standardized and can be modified and reconfigured by editing the package.json and script files. This flexibility is relatively uncommon in other frameworks like React, Vue, and Svelte.

Writing your first Nue component

Creating Nue components differs significantly from Svelte and other frameworks. To create a basic component, assign a name attribute prefixed with @ to the parent element within the component structure and save it with your preferred name.

Nue components can be saved with either a .nue or .htm extension. Files with .htm extensions are automatically highlighted in the code editor, but for the files with .nue extension, you'll need the Nue Language Support extension in VS Code for code highlighting.

As demonstrated below, you can make an HTML attribute dynamic by prefixing it with a colon, allowing it to accept variable properties:

<-- components/logo.nue -->
<div @name="logo">
  <a :href="href">
    <img class="logo" :src="img_src" />
  </a>
</div>
Enter fullscreen mode Exit fullscreen mode

Here's how you use this component and provide variable properties to it.

<logo 
  img_src="img/logo.svg" 
  href="//blog.logrocket.com/" 
/>
Enter fullscreen mode Exit fullscreen mode

I've simplified the Nue JS starter project for you, and it includes all the examples we will cover in the upcoming sections. You can fork it from here if you'd like.

Nue JS component types

In the previous section, you learned how to create a basic, universal, static Nue component. It's important to note that Nue components can come in various types, each tailored to different structures and use cases.

Nue categorizes these component types into three distinct categories: server components, reactive components, and isomorphic components. Their names are quite self-explanatory, but let’s explore each in detail below.

Server components

Server components are used to render static HTML on the server side without state management or event handlers. You would typically employ them when you want to serve content directly from the server to the client — in other words, when you want to implement server-side rendering (SSR).

You can define server components dynamically in the scripts/render.js file, render them, and then add them to the final HTML for a given page:

// scripts/render.js
import { render } from 'nuejs-core';

// Define a component for a product card
const serverComponent = `
<div @name="server-component">
  <h3>{componentTitle}</h3>
  <p>{componentDesc}</p>
</div>
`;

// Render the product card component with some product data
const serverComponentHtml = render(serverComponent, {
  title: '...',
  desc: '...',
});

console.info(serverComponentHtml);
Enter fullscreen mode Exit fullscreen mode

The following screenshots illustrate a server component's markup being logged on the server console. This data cannot be logged in the client console for clear reasons: Developer Terminal With Yellow Arrow And Text Indicating Lines Where Nue Js Server Component Markup Is Logged On Server Console Alternatively, you can place any components you want to render on the server in a single file and then fetch them in the scripts/render.js file.

You can also organize the components in different files and utilize the renderFile function from the Nue JS core to render them, and subsequently output the rendered result as needed:

// scripts/render.js
async function renderServerComponent(url, ops) {
  try {
    // Render the product card component with some product data
    const serverComponentHtml = await renderFile(url, ops)
    return serverComponentHtml
  } catch (error) {
    console.error(error)
    return '' // or handle the error as needed
  }
}

export default async function () {
  ...
  let logoComponentHtml = await renderServerComponent(
    './src/components/logo.nue',
    {
      href: '#',
      img_src: 'img/logo.svg',
    }
  )
  console.log(logoComponentHtml)
  ...
}
Enter fullscreen mode Exit fullscreen mode

The above example shows how to create a utility function that takes a component's file path and some arguments to help construct the component on the server side.

For more details, you can locate the entire scripts/render.js file here, which encompasses not only rendering the components but also rendering the entire page and injecting data and critical styles into it using the Nue JS core and Node functions.

Reactive components

Reactive components play a key role in client-side rendering (CSR). They can support state, reactivity, and event handling, making them suitable for creating interactive elements.

Reactive components in Nue, also known as islands, can be defined within the HTML structure. In our sample Nue project, the reactive components are defined in the islands.nue file and compiled in the scripts/compile.js file.

Here's an example of a reactive Nue component:

<!-- Reactive Component -->
<div @name="reactive-component">
  <p>The below button count clicks on it.</p>
  <button @click="index++">Click me { index }</button>
  <script>
    index = 0
  </script>
</div>
Enter fullscreen mode Exit fullscreen mode

As mentioned earlier, you have the option to either place all the reactive components in one file — in our case, islands.nue — and then process it in scripts/compile.js, or you can organize each reactive component separately and compile them individually, which I think is a bit tedious:

// scripts/compile.js
import { compileFile } from 'nuejs-core';

export default async function (to = 'www/islands.js') {
  await compileFile('src/components/reactive-component.nue', to);
  console.info('compiled', to);
}
Enter fullscreen mode Exit fullscreen mode

All this compiled code will land right into the www/islands.js file, which can be enqueued in the index.html and other markup files in the www directory.

Isomorphic components

Isomorphic components in Nue come in two flavors: universal and hybrid. Universal components can be rendered on both the server and client, while hybrid components combine server-side and client-side rendering.

The component we previously learned to create was universal in nature. You can revisit it for reference.

You can think of hybrid components as having two sides: one for the server to ensure content is visible without JavaScript, and another for the client to add interactive features.

The Nue JS Docs explain hybrid components using the example of a video player on a website. The server part ensures the video is accessible, which is crucial for search engines and those who prefer a basic experience. When JavaScript is available, the client part takes over, making the video interactive with play and pause buttons.

Nue smoothly blends these two sides, with a Nue “island" acting as a placeholder for the client part in the generated HTML. When it's time for interactivity, the island gets filled with client code and data, making the web experience both accessible and dynamic.

Event handling in Nue JS

Event handling in Nue is similar to event handling in Svelte and Vue, offering various event modifiers to control behavior. However, Nue has its own unique syntax and usage, which we will explore in this section to enable you to create dynamic and interactive Nue components.

To handle events in Nue, you use the @ directive followed by the event type. In the next few sections, we will delve into different event types, providing a more detailed understanding of their usage and syntax.

Inline handlers

Inline handlers are a straightforward way to handle events directly on an attribute. They are ideal for simple expressions, such as:

<button @click="alert('Hello!')">Click me!</button>
Enter fullscreen mode Exit fullscreen mode

In this example, clicking the button triggers the alert() function with the message Hello!. We have already observed a similar example earlier in the section on Reactive components.

Method handlers

For more complex functionality and the ability to handle arguments, you can use method handlers. First, create a function in your component's script, and then bind it to the event attribute:

<button @click="greet('John Doe')">Click me!</button>
<script>
function greet(name) {
  alert(`Hello, ${name}!`);
}
</script>
Enter fullscreen mode Exit fullscreen mode

This configuration calls the greet() function with the argument John Doe when the button is clicked.

Event modifiers

Event modifiers provide shortcuts for common DOM event manipulation tasks. For example, the :preventDefault modifier prevents the default behavior of the event:

<a 
  href="#" 
  @click:preventDefault="console.log('Link clicked!')"
>Click me!</a>
Enter fullscreen mode Exit fullscreen mode

This logs Link clicked! to the console upon clicking the link without navigating to the href value.

Key modifiers

Key modifiers bind an event handler to a specific keyboard key. Consider the :enter modifier, which associates the event handler with the Enter key:

<input @keyup:enter="search()">
Enter fullscreen mode Exit fullscreen mode

This calls the search() function when the user presses Enter while typing in the input field.

Handling multiple events

You can manage multiple events on the same element by separating them with commas. For example:

<button 
  @click:preventDefault="greet('John Doe')" 
  @mouseover="console.log('Button hovered!')"
>Click me!</button>
Enter fullscreen mode Exit fullscreen mode

This configuration calls the greet() function with the argument John Doe upon clicking the button and logs Button hovered! to the console when hovering over the button.

Control flow utilities in Nue JS

Like Svelte and other JavaScript frameworks, Nue provides conditional directives and loops to control content rendering and iterate through data structures. Let's explore these control flow utilities with some examples.

Conditional directives

Conditional directives allow you to render content based on specific conditions. The primary conditional directive in Nue is :if. It accepts an expression as its argument, and the content enclosed within it will only be rendered if the expression evaluates to true.

For instance, consider the following code snippet. It will display the <h1> element only if the isLoggedIn variable is true:

<h1 :if="isLoggedIn">Welcome, user!</h1>
Enter fullscreen mode Exit fullscreen mode

To handle the case when the expression evaluates to false, you can use the :else directive. Here's an example:

<h1 :if="isLoggedIn">Welcome, user!</h1>
<p :else>Please log in.</p>
Enter fullscreen mode Exit fullscreen mode

You can also use the :elif directive to cater to multiple conditions. The following code snippet renders the <h1> element if isLoggedIn is true, the <h2> element if isAdmin is true, and the <p> element if both conditions are false:

<h1 :if="isLoggedIn">Welcome, user!</h1>
<h2 :elif="isAdmin">Welcome, admin!</h2>
<p :else>Please log in.</p>
Enter fullscreen mode Exit fullscreen mode

Loops

Loops are essential for iterating over arrays, objects, and components. The most commonly used loop directive in Nue is :for. This directive takes an expression as its argument, and its content is rendered for each item in the array, object, or component.

Here's an example that renders a <li> element for each item in the items array:

<ul>
  <li :for="item in items">{ item }</li>
</ul>
Enter fullscreen mode Exit fullscreen mode

To keep track of each item's state in the loop, you can use the :key directive. This is especially useful when working with lists of items. In the following code, a unique key is specified for each item in the loop using the id property:

<ul>
  <li :for="item in items" :key="item.id">{ item }</li>
</ul>
Enter fullscreen mode Exit fullscreen mode

Conditional directives and loops together

For more complex logic, combine conditional directives and loops. For instance, the following example renders a <li> element for each item in the items array, but only if the item.isImportant property is true:

<ul>
  <li :for="item in items" :if="item.isImportant">{ item }</li>
</ul>
Enter fullscreen mode Exit fullscreen mode

Nesting conditional directives and loops generate a <ul> element for each item in the items array, with <li> elements created for each item in the item.subItems array within the :for directive.

<ul>
  <li :for="item in items">
    <ul>
      <li :for="subItem in item.subItems">{ subItem }</li>
    </ul>
  </li>
</ul>
Enter fullscreen mode Exit fullscreen mode

By combining conditional directives and loops, you can construct intricate and dynamic user interfaces tailored to your application's needs.

Styling Nue JS with CSS

Nue advocates for using external stylesheets to follow the software design principle of separation of concerns. It does not support using style tags or CSS-in-JS at the component level, emphasizing the importance of maintaining this separation.

Maintaining separate CSS files is consistent with Nue's approach and is also a best practice in general. This practice keeps each CSS file dedicated to its specific task, making management and maintenance significantly easier.

If you examine the scripts/render.js file, you will notice that the framework recommends reading critical CSS and adding its contents to the content.data file to use later in the page as inline styles:

// scripts/render.js
export default async function() {
  ...
  const primary_css = await read('primary.css', 'www/css')
  const data = yaml.load(await read('content.data'))
  data.primary_css = primary_css.replace(/\s+/g, ' ')
  ...
}
Enter fullscreen mode Exit fullscreen mode

You can now utilize the primary_css property in a layout file to import the primary CSS data and place it within style tags as inline CSS styles. This approach ensures that the initial UI loads without blocking anything, and the rest of the component styles can be added as needed.

While you can use inline CSS styles within components, it is not a recommended styling method as it can complicate the maintenance process.

Upcoming Nue tools

Nue is about to introduce several noteworthy features, starting with Nue CSS, which revitalizes cascaded styling, and Nue UI, a user-friendly UI library.

Eventually, Nue plans to roll out additional tools, including:

  • Nue MVC, which simplifies the development of scalable applications with the MVC architecture
  • Nuemark, which enhances Markdown capabilities
  • NueKit, which streamlines development similar to SvelteKit, Next.js, and Nuxt.js

With these planned features, it’s evident that Nue has the potential for growth and can offer better solutions to frontend development challenges in the future.

Conclusion

While Nue is still in its early development stages, it shows promise as a powerful framework. However, it's not enough to label Nue as the fastest framework solely based on the fewer lines of code used to create some components than other frameworks.

Working with Nue will require a substantial amount of manual work, including configuring and optimizing build scripts to tailor them to the unique requirements of each project. Furthermore, Nue currently lacks a straightforward method for organizing components, a command-line interface (CLI), and fundamental features like hot-reloading. These issues may be tackled in future releases, particularly with the introduction of NueKit.

On the other hand, Svelte is a more mature framework than Nue and is already performing exceptionally well with a lot of developer-friendly features. I personally find it excellent for creating advanced as well as lightweight JavaScript apps.

If you're interested in exploring a new JavaScript framework with promising features, Nue might be an excellent choice for you. If you prefer a well-established framework with a larger community, a great developer experience, and widespread adoption, then Svelte is the way to go.

I recommend trying both frameworks to determine which one aligns with your preferences. Using Nue for more applications can significantly contribute to identifying issues and fostering its ongoing development and growth.


Are you adding new JS libraries to improve performance or build new features? What if they’re doing the opposite?

There’s no doubt that frontends are getting more complex. As you add new JavaScript libraries and other dependencies to your app, you’ll need more visibility to ensure your users don’t run into unknown issues.

LogRocket is a frontend application monitoring solution that lets you replay JavaScript errors as if they happened in your own browser so you can react to bugs more effectively.

LogRocket Signup

LogRocket works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store. Instead of guessing why problems happen, you can aggregate and report on what state your application was in when an issue occurred. LogRocket also monitors your app’s performance, reporting metrics like client CPU load, client memory usage, and more.

Build confidently — Start monitoring for free.

Top comments (3)

Collapse
 
kirilldedeshin profile image
Kirill Dedeshin

Very nice!

Collapse
 
enoshyu profile image
유종훈 • Edited

Thanks for your post. Well.. I want to translate this post into Korean.
Do you mind if I translate your post?

Collapse
 
dugnist profile image
Alexey Dugnist

Just what you need to replace the over-complicated Next.js