Skip to content

How to Serve a Single Page Application (SPA) using Rollup.js and Web Dev Server

This article was written over 18 months ago and may contain information that is out of date. Some content may be relevant but please refer to the relevant official documentation or available resources for the latest information.

In a previous post, I explained How to setup a TypeScript project using Rollup.js. In that article, I covered the necessary steps to have a Project Setup ready to generate a build using TypeScript and Rollup configurations.

So let's take that project as a starting point to serve a Single-page Application using modern web tools.

What is a SPA (Single-page Application)?

According to MDN Documentation:

An SPA (single-page application) is a web app implementation that loads only a single web document, and then updates the body content of that single document via JavaScript APIs such as XMLHttpRequest and Fetch when different content is to be shown.

A single-page application allows updating only some portions of the current page instead of doing a page refresh. Think about some applications you use every day:

  • Gmail
  • Facebook
  • Twitter
  • LinkedIn

All of these applications have been built with the user experience in mind along with a good loading speed and navigation between pages.

There are very good reasons to keep building applications following the SPAs approach.

What is Web Dev Server?

Web Dev Server, as its name states, it's a web server for development. It helps development using native browser features like ES modules. It has a plugin architecture for code transformations.

Web Dev Server is the successor of es-dev-server

It's worth mentioning that Web Dev Server allows configuring auto-reload on file changes along with efficient browser caching for faster reloads. It's configurable and supports rollup plugins too!

Project Setup

Prerequisites

You'll need to have installed the following tools in your local environment:

  • Node.js. Preferably the latest LTS version.
  • A package manager. You can use either NPM or Yarn. This tutorial will use NPM.

Initialize the Project

Let's create a clone or download the project seed before adding the new configurations and tools:

git clone https://github.com/luixaviles/typescript-rollup.git
cd typescript-rollup/
git checkout tags/01-setup-ts-rollup -b 02-serve-spa 

The previous commands will download the project and create a new branch 02-serve-spa to get started.

Source Code Files

Once you have the project ready, open it with your favorite code editor and pay attention to the current project structure:

|- typescript-rollup
    |- src/
        |- math/
            |- math.ts
            |- index.ts
        |- string/
            |- string.ts
            |- index.ts
        |- app.ts
    |- package.json
    |- rollup.config.js
    |- tsconfig.json

Installing Web Dev Server and Concurrently

Let's add some development dependencies to the project.

  • Install Web Dev Server
npm install --save-dev @web/dev-server

As I mentioned before, Web Sev Server will be the main tool to configure and run our project this time.

Also, if you already know es-dev-server tool, used actively on the Open Web Components initiative, you'll understand that this project migrated to Modern Web website. That does not mean anything other than this new tool continues to be actively developed and can be used in any JavaScript project (TypeScript included ;-)).

  • Install Concurrently tool
npm install --save-dev concurrently

If you are familiar with any command-line tool, you may have wanted to run commands in parallel.

Concurrently has the same goal. However, it's hard to keep track of every command output and concurrently allows you to run any command you want. It's possible to kill all of them if anyone fails.

TypeScript Configuration

In this case, the tsconfig.json file will remain the same, without any changes:

{
  "compilerOptions": {
    "target": "es2018",                          
    "module": "esnext",
    "moduleResolution": "node",                     
    "noEmitOnError": true,
    "lib": ["es2017"],                            
    "strict": true,  
    "esModuleInterop": false,                 
    "outDir": "out-tsc",
    "rootDir": "./"
  }
  ,
  "include": ["./src/**/*.ts"]
}

Remember, this file is required to be present in the root of any TypeScript project.

Rollup Configuration

The project is configured to use Rollup as the module bundler. It's possible to run it through command-line parameters. However, if you're looking for advanced functionality, you can consider a rollup.config.js file:

import merge from 'deepmerge';
import { createBasicConfig } from '@open-wc/building-rollup';

const baseConfig = createBasicConfig();

export default merge(baseConfig, {
  input: './out-tsc/src/app.js',
  output: {
      dir: 'dist',
  }
});

This file contains a basic configuration. I's needed to set the input files and the output directory for the build.

Since we intend to compile a Single-page application now, it will be necessary to apply some changes:

import merge from 'deepmerge';
import { createSpaConfig } from '@open-wc/building-rollup';

const baseConfig = createSpaConfig({
  developmentMode: process.env.ROLLUP_WATCH === 'true',
  injectServiceWorker: false
});

export default merge(baseConfig, {
  // any <script type="module"> inside will be bundled by Rollup
  input: './index.html'
});

The baseConfig content will be generated from createSpaConfig, which is defined in @open-wc/building-rollup package.

When createSpaConfig is used, a service worker is generated using Workbox. However, the service worker is injected into the index.html file when injectServiceWorker is enabled.

HTML file as an Input

Once the input parameter is set using an index.html file, any module defined as part of it will be bundled by Rollup. This content will be injected into the HTML file result.

The index.html File

Let's create an index.html file into the root folder with the following content:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>My Single Page Application</title>
</head>
<body>
    <h1>Welcome to your Single Page Application</h1>
    <span>This App uses:</span>
    <ul>
        <li>TypeScript</li>
        <li>Rollup.js</li>
        <li>es-dev-server</li>
    </ul>
    <script type="module" src="./out-tsc/src/app.js"></script>
</body>
</html>

We can say the content of this file is common. However, the most important line would be the reference to the app.js file:

<script type="module" src="./out-tsc/src/app.js"></script>

Let's explain what is happening there:

  • As you will remember, the tsconfig.json file sets "outDir": "out-tsc" and that means the TypeScript compiler will generate the output files in ./out-tsc folder.
  • Then, the index.html file does reference to the entry point of the source code, the compiled version of the ./src/app.ts file.
  • When the Rollup configuration starts to build the app, it will take the module defined in index.html file to generate a bundle ready for it.

Adding Serve and Build Scripts

If you pay attention to the package.json file, it already defines a script to generate the build:

...
"scripts": {
    "build": "rimraf dist && tsc && rollup -c rollup.config.js"
},
...

The change we introduced into the rollup.config.json file doesn't affect the build process.

Now let's move forward with the addition of some scripts to "serve" the application:

... 
"scripts": {
    "tsc:watch": "tsc --watch",
    "start": "concurrently --kill-others --names tsc,web-dev-server \"npm run tsc:watch\" \"web-dev-server --app-index index.html --node-resolve --open --watch\"",
    "build": "rimraf dist && tsc && rollup -c rollup.config.js"
},
...
  • "tsc:watch" is the script to start with the compilation process through tsc, which is the TypeScript compiler. The --watch param stands for a compiler option to run the compiler in watch mode(it triggers recompilation on file changes).
  • "start" is the script to add the execution of some commands in parallel: npm run tsc:watch and web-dev-server that includes some CLI flags.
    • You already noted that concurrently command is called first!
    • The --kill-others parameter will kill all the invoked commands if one dies (either tsc or web-dev-server).

Think for a while how the "start" command is going to look if we're planning to add more configurations in the future: a script that is hard to read and maintain, of course.

Adding the web-dev-server.config.js File

The alternative option to include the CLI flags as parameters is the creation of the web-dev-server.config.js file.

The file extension can be .js, .cjs or .mjs. A .js file will be loaded as an es module or common js module based on your version of node, and the package type of your project.

By default, the Web Dev Server looks at the configuration file in the current working directory.

Let's create the web-dev-server.config.js file in the root folder:

// web-dev-server.config.js

module.exports = {
    port: 8000,
    nodeResolve: true,
    open: true,
    watch: true,
    appIndex: 'index.html',
};

This file now contains the same options we used in the start script with the addition of a custom port number: port: 8000, which can be configured now.

For the sake of simplicity, let's update the start script with a reference to the new configuration file:

... 
"scripts": {
    ...
    "start": "concurrently --kill-others --names tsc,web-dev-server \"npm run tsc:watch\" \"web-dev-server --config web-dev-server.config.js\"",
    ...
},
...

That's it! You're ready to serve your first application using:

npm run start

You should see the following output:

Web Dev Server started...
[web-dev-server] 
[web-dev-server]   Root dir: /Users/luixaviles/projects/typescript-rollup
[web-dev-server]   Local:    http://localhost:8000/
[web-dev-server]   Network:  http://192.168.1.2:8000/
[web-dev-server] 

Also, your default browser will be opened to display the index.html content.

single-page-application rollup web-dev-server

On the right side (when you open the Developer Tools), you'll see the output of the main script file. That is proof that the module is running correctly when the SPA is loaded.

Running the Build

The script is ready and doesn't need an update. Execute the following command:

npm run build

This will generate a dist folder with the following content:

|- dist/
    |- 7b857f5b.js
    |- index.html
    |- ... other scripts

A simple way to serve these files locally would be to use the http-server tool (a command-line http server):

http-server dist/ -o

The output of this command will show you the host and the port you need to use to access the build version of the app:

Starting up http-server, serving dist/
Available on:
  http://127.0.0.1:8080
  http://192.168.1.2:8080
Hit CTRL-C to stop the server
open: http://127.0.0.1:8080

I suggest you review the content of dist/ files and make sure you have http-server installed before running the latest command.

Source Code of the Project

Find the complete project in this GitHub repository: typescript-rollup. Do not forget to give it a star ⭐️ and play around with the code.

Feel free to reach out on Twitter if you have any questions. Follow me on GitHub to see more about my work.

This Dot is a consultancy dedicated to guiding companies through their modernization and digital transformation journeys. Specializing in replatforming, modernizing, and launching new initiatives, we stand out by taking true ownership of your engineering projects.

We love helping teams with projects that have missed their deadlines or helping keep your strategic digital initiatives on course. Check out our case studies and our clients that trust us with their engineering.

You might also like

Understanding Vue's Reactive Data cover image

Understanding Vue's Reactive Data

Introduction Web development has always been about creating dynamic experiences. One of the biggest challenges developers face is managing how data changes over time and reflecting these changes in the UI promptly and accurately. This is where Vue.js, one of the most popular JavaScript frameworks, excels with its powerful reactive data system. In this article, we dig into the heart of Vue's reactivity system. We unravel how it perfectly syncs your application UI with the underlying data state, allowing for a seamless user experience. Whether new to Vue or looking to deepen your understanding, this guide will provide a clear and concise overview of Vue's reactivity, empowering you to build more efficient and responsive Vue 3 applications. So, let’s kick off and embark on this journey to decode Vue's reactive data system. What is Vue's Reactive Data? What does it mean for data to be ”'reactive”? In essence, when data is reactive, it means that every time the data changes, all parts of the UI that rely on this data automatically update to reflect these changes. This ensures that the user is always looking at the most current state of the application. At its core, Vue's Reactive Data is like a superpower for your application data. Think of it like a mirror - whatever changes you make in your data, the user interface (UI) reflects these changes instantly, like a mirror reflecting your image. This automatic update feature is what we refer to as “reactivity”. To visualize this concept, let's use an example of a simple Vue application displaying a message on the screen: ` In this application, 'message' is a piece of data that says 'Hello Vue!'. Let's say you change this message to 'Goodbye Vue!' later in your code, like when a button is clicked. ` With Vue's reactivity, when you change your data, the UI automatically updates to 'Goodbye Vue!' instead of 'Hello Vue!'. You don't have to write extra code to make this update happen - Vue's Reactive Data system takes care of it. How does it work? Let's keep the mirror example going. Vue's Reactive Data is the mirror that reflects your data changes in the UI. But how does this mirror know when and what to reflect? That's where Vue's underlying mechanism comes into play. Vue has a behind-the-scenes mechanism that helps it stay alerted to any changes in your data. When you create a reactive data object, Vue doesn't just leave it as it is. Instead, it sends this data object through a transformation process and wraps it up in a Proxy. Proxy objects are powerful and can detect when a property is changed, updated, or deleted. Let's use our previous example: ` Consider our “message” data as a book in a library. Vue places this book (our data) within a special book cover (the Proxy). This book cover is unique - it's embedded with a tracking device that notifies Vue every time someone reads the book (accesses the data) or annotates a page (changes the data). In our example, the reactive function creates a Proxy object that wraps around our state object. When you change the 'message': ` The Proxy notices this (like a built-in alarm going off) and alerts Vue that something has changed. Vue then updates the UI to reflect this change. Let’s look deeper into what Vue is doing for us and how it transforms our object into a Proxy object. You don't have to worry about creating or managing the Proxy; Vue handles everything. ` In the example above, we encapsulate our object, in this case, “state”, converting it into a Proxy object. Note that within the second argument of the Proxy, we have two methods: a getter and a setter. The getter method is straightforward: it merely returns the value, which in this instance is “state.message” equating to 'Hello Vue!' Meanwhile, the setter method comes into play when a new value is assigned, as in the case of “state.message = ‘Hey young padawan!’”. Here, “value” becomes our new 'Hey young padawan!', prompting the property to update. This action, in turn, triggers the reactivity system, which subsequently updates the DOM. Venturing Further into the Depths If you have been paying attention to our examples above, you might have noticed that inside the Proxy method, we call the functions track and trigger to run our reactivity. Let’s try to understand a bit more about them. You see, Vue 3 reactivity data is more about Proxy objects. Let’s create a new example: ` In this example, when you click on the button, the message's value changes. This change triggers the effect function to run, as it's actively listening for any changes in its dependencies. How does the effect property know when to be called? Vue 3 has three main functions to run our reactivity: effect, track, and trigger. The effect function is like our supervisor. It steps in and takes action when our data changes – similar to our effect method, we will dive in more later. Next, we have the track function. It notes down all the important data we need to keep an eye on. In our case, this data would be state.message. Lastly, we've got the trigger function. This one is like our alarm bell. It alerts the effect function whenever our important data (the stuff track is keeping an eye on) changes. In this way, trigger, track, and effect work together to keep our Vue application reacting smoothly to changes in data. Let’s go back to them: ` Tracking (Dependency Collection) Tracking is the process of registering dependencies between reactive objects and the effects that depend on them. When a reactive property is read, it's "tracked" as a dependency of the current running effect. When we execute track(), we essentially store our effects in a Set object. But what exactly is an "effect"? If we revisit our previous example, we see that the effect method must be run whenever any property changes. This action — running the effect method in response to property changes — is what we refer to as an "Effect"! (computed property, watcher, etc.) > Note: We'll outline a basic, high-level overview of what might happen under the hood. Please note that the actual implementation is more complex and optimized, but this should give you an idea of how it works. Let’s see how it works! In our example, we have the following reactive object: ` We need a way to reference the reactive object with its effects. For that, we use a WeakMap. Which type is going to look something like this: ` We are using a WeakMap to set our object state as the target (or key). In the Vue code, they call this object targetMap. Within this targetMap object, our value is an object named depMap of Map type. Here, the keys represent our properties (in our case, that would be message and showSword), and the values correspond to their effects – remember, they are stored in a Set that in Vue 3 we refer to as dep. Huh… It might seem a bit complex, right? Let's make it more straightforward with a visual example: With the above explained, let’s see what this Track method kind of looks like and how it uses this targetMap. This method essentially is doing something like this: ` At this point, you have to be wondering, how does Vue 3 know what activeEffect should run? Vue 3 keeps track of the currently running effect by using a global variable. When an effect is executed, Vue temporarily stores a reference to it in this global variable, allowing the track function to access the currently running effect and associate it with the accessed reactive property. This global variable is called inside Vue as activeEffect. Vue 3 knows which effect is assigned to this global variable by wrapping the effects functions in a method that invokes the effect whenever a dependency changes. And yes, you guessed, that method is our effect method. ` This method behind the scenes is doing something similar to this: ` The handling of activeEffect within Vue's reactivity system is a dance of careful timing, scoping, and context preservation. Let’s go step by step on how this is working all together. When we run our Effect method for the first time, we call the get trap of the Proxy. ` When running the get trap, we have our activeEffect so we can store it as a dependency. ` This coordination ensures that when a reactive property is accessed within an effect, the track function knows which effect is responsible for that access. Trigger Method Our last method makes this Reactive system to be complete. The trigger method looks up the dependencies for the given target and key and re-runs all dependent effects. ` Conclusion Diving into Vue 3's reactivity system has been like unlocking a hidden superpower in my web development toolkit, and honestly, I've had a blast learning about it. From the rudimentary elements of reactive data and instantaneous UI updates to the intricate details involving Proxies, track and trigger functions, and effects, Vue 3's reactivity is an impressively robust framework for building dynamic and responsive applications. In our journey through Vue 3's reactivity, we've uncovered how this framework ensures real-time and precise updates to the UI. We've delved into the use of Proxies to intercept and monitor variable changes and dissected the roles of track and trigger functions, along with the 'effect' method, in facilitating seamless UI updates. Along the way, we've also discovered how Vue ingeniously manages data dependencies through sophisticated data structures like WeakMaps and Sets, offering us a glimpse into its efficient approach to change detection and UI rendering. Whether you're just starting with Vue 3 or an experienced developer looking to level up, understanding this reactivity system is a game-changer. It doesn't just streamline the development process; it enables you to create more interactive, scalable, and maintainable applications. I love Vue 3, and mastering its reactivity system has been enlightening and fun. Thanks for reading, and as always, happy coding!...

Testing a Fastify app with the NodeJS test runner cover image

Testing a Fastify app with the NodeJS test runner

Introduction Node.js has shipped a built-in test runner for a couple of major versions. Since its release I haven’t heard much about it so I decided to try it out on a simple Fastify API server application that I was working on. It turns out, it’s pretty good! It’s also really nice to start testing a node application without dealing with the hassle of installing some additional dependencies and managing more configurations. Since it’s got my stamp of approval, why not write a post about it? In this post, we will hit the highlights of the testing API and write some basic but real-life tests for an API server. This server will be built with Fastify, a plugin-centric API framework. They have some good documentation on testing that should make this pretty easy. We’ll also add a SQL driver for the plugin we will test. Setup Let's set up our simple API server by creating a new project, adding our dependencies, and creating some files. Ensure you’re running node v20 or greater (Test runner is a stable API as of the 20 major releases) Overview * index.js - node entry that initializes our Fastify app and listens for incoming http requests on port 3001 * app.js - this file exports a function that creates and returns our Fastify application instance * sql-plugin.js - a Fastify plugin that sets up and connects to a SQL driver and makes it available on our app instance Application Code A simple first test For our first test we will just test our servers index route. If you recall from the app.js code above, our index route returns a 501 response for “not implemented”. In this test, we're using the createApp function to create a new instance of our Fastify app, and then using the inject method from the Fastify API to make a request to the / route. We import our test utilities directly from the node. Notice we can pass async functions to our test to use async/await. Node’s assert API has been around for a long time, this is what we are using to make our test assertions. To run this test, we can use the following command: By default the Node.js test runner uses the TAP reporter. You can configure it using other reporters or even create your own custom reporters for it to use. Testing our SQL plugin Next, let's take a look at how to test our Fastify Postgres plugin. This one is a bit more involved and gives us an opportunity to use more of the test runner features. In this example, we are using a feature called Subtests. This simply means when nested tests inside of a top-level test. In our top-level test call, we get a test parameter t that we call methods on in our nested test structure. In this example, we use t.beforeEach to create a new Fastify app instance for each test, and call the test method to register our nested tests. Along with beforeEach the other methods you might expect are also available: afterEach, before, after. Since we don’t want to connect to our Postgres database in our tests, we are using the available Mocking API to mock out the client. This was the API that I was most excited to see included in the Node Test Runner. After the basics, you almost always need to mock some functions, methods, or libraries in your tests. After trying this feature, it works easily and as expected, I was confident that I could get pretty far testing with the new Node.js core API’s. Since my plugin only uses the end method of the Postgres driver, it’s the only method I provide a mock function for. Our second test confirms that it gets called when our Fastify server is shutting down. Additional features A lot of other features that are common in other popular testing frameworks are also available. Test styles and methods Along with our basic test based tests we used for our Fastify plugins - test also includes skip, todo, and only methods. They are for what you would expect based on the names, skipping or only running certain tests, and work-in-progress tests. If you prefer, you also have the option of using the describe → it test syntax. They both come with the same methods as test and I think it really comes down to a matter of personal preference. Test coverage This might be the deal breaker for some since this feature is still experimental. As popular as test coverage reporting is, I expect this API to be finalized and become stable in an upcoming version. Since this isn’t something that’s being shipped for the end user though, I say go for it. What’s the worst that could happen really? Other CLI flags —watch - https://nodejs.org/dist/latest-v20.x/docs/api/cli.html#--watch —test-name-pattern - https://nodejs.org/dist/latest-v20.x/docs/api/cli.html#--test-name-pattern TypeScript support You can use a loader like you would for a regular node application to execute TypeScript files. Some popular examples are tsx and ts-node. In practice, I found that this currently doesn’t work well since the test runner only looks for JS file types. After digging in I found that they added support to locate your test files via a glob string but it won’t be available until the next major version release. Conclusion The built-in test runner is a lot more comprehensive than I expected it to be. I was able to easily write some real-world tests for my application. If you don’t mind some of the features like coverage reporting being experimental, you can get pretty far without installing any additional dependencies. The biggest deal breaker on many projects at this point, in my opinion, is the lack of straightforward TypeScript support. This is the test command that I ended up with in my application: I’ll be honest, I stole this from a GitHub issue thread and I don’t know exactly how it works (but it does). If TypeScript is a requirement, maybe stick with Jest or Vitest for now 🙂...

How to Update the Application Title based on Routing Changes in Angular cover image

How to Update the Application Title based on Routing Changes in Angular

Have you tried to update the document's title of your application? Maybe you're thinking that applying interpolation should be enough: ` That solution is not going to work since the element is outside of the scope of the Angular application. In fact, the root component of your app is within tag, and the title is part of the element. Luckily, Angular provides the Title service with the methods to read the current title of the application, and a setTitle(title) to update that value. However, what happens if you need to update the title on routing changes? Also, you may consider updating it on certain components for Analytics purposes. In this blog post, I'll explain step-by-step how to create a custom Title service to have full control over the title of the current HTML document for your application. Project Setup Prerequisites You'll need to have installed the following tools in your local environment: - Node.js. Preferably the latest LTS version. - A package manager. You can use either NPM or Yarn. This tutorial will use NPM. Creating the Angular Project Let's assume we'll need to build an application with the following routes as requirements: ` Now, let's create the project from scratch using the Angular CLI tool. ` This command will initialize a base project using some configuration options: - --routing. It will create a routing module. - --prefix corp. It defines a prefix to be applied to the selectors for created components(corp in this case). The default value is app. - --style css. The file extension for the styling files. - --skip-tests. it avoids the generations of the .spec.ts files, which are used for testing Creating the Modules and Components Once we got the initial structure of the app, we'll continue running the following commands to create a separate module for /home and /products, which are the main paths of the project: ` * The --routing flag can be using also along with ng generate module to create a routing configuration file for that module. Creating the Title Service Similar to the previous section, we will create a shared module to hold the Title service. Both can be generated with the following commands: ` * The --module app flag is used to "link" the brand new module to the pre-existing app.module.ts file. The Routing Configuration Open the app-routing.module.ts file, and create the initial routes. ` * By default, the application will redirect to the home path. * When the router loads the home path, a HomeComponent will be rendered. * The products path will be loaded using the _lazy loading_ feature. Pay attention to the data provided to the home path. It contains the configured title through pageTitle string. Next, open the products-routing.module.ts file to enable an additional configuration to load the _Products_ and the _Product Detail_ page. ` * The router will render the ProductsComponent by default when the path matches to /products. This route also defines custom data to be rendered as titles later. * When the path also adds an Id on /products/:id, the router will render the ProductDetailComponent. The Title Service Implementation It's time to implement the custom Title Service for our application. ` The above service implementation could be understood in just a few steps. * First, we'll need to make sure to inject the Router, ActivatedRoute and Title services in the constructor. * The title$ attribute contains the initial value for the title("Corp"), which will be emitted through a _BehaviorSubject_. * The titleRoute$ is an Observable ready to emit any pageTitle value defined in the current route. It may use the parent's _pageTitle_ otherwise. * The titleState$ is an Observable ready to _listen_ to either title$ or titleRoute$ values. In case incoming value is defined, it will call the Angular Title service to perform the update. * The getPageTitle method will be in charge of obtaining the pageTitle of the current route if it is defined or the title of the parent otherwise. Injecting the Title Service One easy way to apply the custom Title Service in the whole application is by updating the app.module.ts file and injecting it into the constructor. ` In that way, once the default component gets rendered, the title will be displayed as Corp - Home. If you click on _Go to Products_ link, then a redirection will be performed and the Title service will be invoked again to display Corp - Products at this time. However, we may need to render a different title according to the product detail. In this case, we'll show Corp - Product Detail - :id where the Id matches with the current route parameter. ` Let's explain the implementation of this component: * The constructor injects the ActivatedRoute and the custom TitleService. * The productId$ is the _Observable_ which is going to emit the Id parameter every time it changes in the URL. * Once the component gets initialized, we'll need to _subscribe_ to the productId$ _Observable_ and then emit a new value for the title after creating a new string using the id. That's possible through the titleService.title$.next() method. * When the component gets _destroyed_, we'll need to _unsubscribe_ from the productIdSubscription. We're ready to go! Every time you select a product, the ProductDetail component will be rendered, and the title will be updated accordingly. Live Demo and Source Code Want to play around with the final application? Just open the following link in your browser: https://luixaviles.github.io/angular-update-title. Find the complete angular project in this GitHub repository: angular-update-title-service. Do not forget to give it a star ⭐️, and play around with the code. Feel free to reach out on Twitter if you have any questions. Follow me on GitHub to see more about my work....

Building a Stripe App: A Step-by-Step Guide to QR Code Generation cover image

Building a Stripe App: A Step-by-Step Guide to QR Code Generation

Building a Stripe App: A Step-by-Step Guide to QR Code Generation Why Build a Stripe App? I recently participated in an audio space with the Stripe team, and something they said really stuck with me: the Stripe app store is a growing area that isn't overly saturated yet. There's a lot of potential for new apps, and companies can use this opportunity to grow. I work at a company called This Dot Labs, and we've created several Stripe apps and even own one. After looking at the data, I can confirm that the Stripe team was right! Creating a QR Code Generator App For this tutorial, we'll build a QR code app that can take a URL and generate a code for it. This is a good use case to help you understand the ins and outs of Stripe's developer tools. Why QR Codes? QR codes are useful tools that have become common in e-commerce, restaurants, and other industries. While Stripe already has a QR code tool, we'll make our own to familiarize ourselves with their syntax and problem-solving approaches. Project Structure Before we dive into the implementation, let's look at the structure of our Stripe App QR Code project: * .vscode: Contains settings for Visual Studio Code * source/views: Holds the main application views * .gitignore: Specifies files to ignore in version control * stripe-app.json: Defines the Stripe app configuration * ui-extensions.d.ts: TypeScript declaration file for UI extensions * .build: this is where the built Stripe app gets placed. Step-by-Step Implementation 1\. Install Stripe Locally First, you need to install Stripe on your local machine. The documentation provides great instructions for this: * For Mac users: Use Brew to install * For Windows users: Download the package and add it to your environment variables You can find the details here in the stripe docs to install the Stripe CLI https://docs.stripe.com/stripe-cli When using Windows, you must do stripe login from Powershell, NOT from Git bash or any other tool. After the server is up, then you can continue using git bash for everything else. After stripe login, you need to enter stripe apps start. Once you do that, the server is up and running and you can go back to using git bash or any other tool. 2\. Install Dependencies We'll be using an extra package for QR code generation. Install it using npm: ` 3\. Set Up the Main Component Let's look at the home.tsx file, where we'll use Stripe's UI components: ` These components are similar to other UI libraries like Bootstrap or Tailwind CSS. 4\. Create the UI Structure Our app will have: * An input field for the URL * Validation using a regex pattern * Error handling for invalid URLs * QR code generation and display Here is the Home.tsx file that is located in the src/views folder ` * ContextView` is at the top level of the app where we see the Title and the link to the Stripe Docs that we placed in our Context View. * Box is how you use Divs. * Banners can be used to show notification errors or any other item you wish to display. * Textfields are input fields. * Everything else is pretty self-explanatory. 5\. Handle Content Security Policy One problem I personally ran into was when I tried to redirect users, the Stripe policies would block it since I did not express that I knew what it was doing. I had to go into the stripe-app.json file and mention the specific security policies. For this particular exercise, I kept these as null. This is my stripe-app.json file. ` 6\. Configure App Views As you can see here, the stripe-app.json file shows the views for each file I have. The Home.tsx file and the Invoice.tsx are also included This is our way of saying that for each view we have, show the app functionality on that page. Our stripe-app.json file will show it but also, the manifest.js file in our .build folder will also show the same. Any view that doesn't have a file will not show the application's functionality. So, if I were to go to transactions, the app would not show the same logic as the home or invoices page. By following these steps, you'll have a fully functional QR code generator app for Stripe. This is just a simple example, but the potential for Stripe apps is massive, especially for businesses serving e-commerce customers. If you need help or get stuck, don't hesitate to reach out, danny.thompson@thisdot.co. The Stripe team is also very active in answering questions, so leverage them as a resource. Happy coding!...

Let's innovate together!

We're ready to be your trusted technical partners in your digital innovation journey.

Whether it's modernization or custom software solutions, our team of experts can guide you through best practices and how to build scalable, performant software that lasts.

Prefer email? hi@thisdot.co