CDN-Starter

A modern starter kit for building and deploying custom JavaScript/TypeScript to Webflow and other no-code platforms.

TypescriptTypescriptWebflowWebflowNPMNPMjsDelivrjsDelivr
CDN-Starter

What is CDN-Starter?

CDN-Starter is a production-ready scaffolding tool that gives you everything you need to write custom TypeScript or JavaScript, bundle it using esbuild, and publish it to npm — so you can load it on any no-code platform like Webflow, Framer, or Squarespace through a single CDN link.

Think of it as a bridge between the developer world and the no-code world. You get the full power of TypeScript, modern tooling, and proper version control, while your no-code site gets a clean, fast script delivered through a global CDN. No webpack, no Vite config rabbit holes, no guesswork. Just one command to scaffold, and you're writing code in minutes.

It comes preconfigured with a dev server with live reload, esbuild for blazing-fast builds, ESLint and Prettier for code quality, TypeScript for type safety, and Changesets for versioning and publishing. You don't have to set up or configure any of this yourself.

The Problem

If you've ever tried adding custom code to Webflow or any no-code platform, you know the pain. The experience usually looks something like this:

You start by writing raw JavaScript directly in an embed block. There's no autocomplete, no error checking, no way to split your code into modules, and no version history. As your logic grows, that embed block becomes a nightmare to maintain.

So you try to set up a proper dev environment. You install a bundler, configure TypeScript, figure out how to output a single file, and then manually upload it somewhere or paste it back into your site. Every time you make a change, you repeat the process. There's no clean workflow for going from "I wrote code on my machine" to "it's running on my live site."

Most developers end up stuck with one of these situations:

Messy inline scripts with no type safety, no modules, and no way to test locally. Over-engineered setups copied from full-stack boilerplates that are way too heavy for what you actually need. Zero versioning, so every change you push is a breaking risk in production with no way to roll back.

CDN-Starter exists to eliminate all of that. One command gives you a clean, minimal project with a fast dev server, TypeScript, linting, formatting, and a publish-to-CDN pipeline — all ready to go.

Getting Started

Prerequisites

Before you begin, make sure you have two things installed on your machine: Node.js version 18 or above, and pnpm version 10 or above. These are the only requirements.

You can verify both by running:

node -v
pnpm -v

If Node.js isn't installed, head to nodejs.org and grab the latest LTS version. For pnpm, you can install it globally through npm:

npm install -g pnpm

pnpm is used instead of npm for dependency management because it's significantly faster and more disk-efficient. It uses a content-addressable store, which means packages are shared across all your projects instead of being duplicated in every node_modules folder. You'll notice the difference immediately on install times.

Create a New Project

Once your prerequisites are ready, scaffold a new project with a single command:

npm create cdn-starter@latest my-project

Replace my-project with whatever you want to name your project. This generates a fully configured project folder with everything already wired up — TypeScript config, esbuild build script, linting rules, formatting config, and a publish workflow. You don't need to touch any of it.

After the project is created, move into the folder and install dependencies:

cd my-project
pnpm install

That's it. Your project is ready. No additional setup needed.

Update Your Project Info

Before you start writing code, open package.json and update it with your own project details. Only modify the fields shown below — everything else in the file controls the build system, scripts, and publishing pipeline, and should be left as is.

package.json
{
  "name": "your-project-name",
  "version": "0.0.0",
  "description": "A short description of what your project does",
  "homepage": "https://your-site.com",
  "license": "MIT",
  "keywords": ["webflow", "custom-code"],
  "author": {
    "name": "Your Name",
    "url": "https://your-site.com"
  }
}

The name field is especially important because it becomes your npm package name. Choose something unique and descriptive. If you're publishing under an npm organization, prefix it like @your-org/your-project-name.

The version field starts at 0.0.0 intentionally. Changesets will handle incrementing this for you when you publish. Don't manually bump it.

How It Works

Understanding Entry Points

This is the most important concept in CDN-Starter. Entry points tell the bundler which files to compile. Not every file in your src/ folder gets built automatically — only the ones you explicitly list.

Open bin/build.js and you'll see something like this:

bin/build.js
const ENTRY_POINTS = [
  "src/index.ts",
  "src/styles/global.css",
];

Each path listed here becomes a separate output file in the dist/ folder. The folder structure is mirrored exactly, so src/index.ts compiles to dist/index.js, and src/styles/global.css compiles to dist/styles/global.css.

When you add a new feature or page-specific script, create the file in src/ and then add its path to this array. For example, if you're building a custom slider for your homepage:

bin/build.js
const ENTRY_POINTS = [
  "src/index.ts",
  "src/styles/global.css",
  "src/home/slider.ts",
];

This will compile to dist/home/slider.js, which you can then load independently on just your homepage. This approach keeps your bundles small — each page only loads the scripts it actually needs instead of one giant bundle.

If you forget to add a file to the entry points array, it simply won't be compiled. The build won't error out, but the file won't appear in dist/. So if something seems missing after a build, check here first.

Development Workflow

Start the dev server with:

pnpm dev

This does three things simultaneously. It watches every file in your src/ folder for changes and rebuilds instantly when you save. It serves the compiled files locally at http://localhost:3000 so you can test them. And it displays a table in your terminal showing every available file with its local URL.

The dev server is incredibly fast because it's powered by esbuild, which compiles TypeScript to JavaScript in milliseconds — not seconds. You'll barely notice the rebuild happening.

During development, you can reference your local files in your Webflow project temporarily by pointing script tags to http://localhost:3000/index.js (or whatever path your file is at). This lets you see changes in real time on your actual Webflow site while developing. Just remember to switch back to the CDN URL before going live.

A typical development workflow looks like this: start the dev server, write your TypeScript code, save the file, watch it rebuild in your terminal, and refresh your Webflow page to see the changes. It's a tight feedback loop that makes working with custom code actually enjoyable.

Production Build

When your code is ready to ship, run:

pnpm build

This is different from the dev build in a few important ways. The output is minified, meaning all whitespace, comments, and unnecessary characters are stripped to reduce file size. Tree-shaking is applied, which removes any code that isn't actually used. And the target is set to ES2020, which gives you modern JavaScript features while still supporting all current browsers.

The compiled files land in the /dist directory. These are the final, optimized files that will be published to npm and served through the CDN. Never edit files in dist/ directly — they get overwritten on every build.

You can inspect the dist/ folder after building to verify everything looks correct. The file sizes should be noticeably smaller than your source files.

Publishing to npm

CDN-Starter uses Changesets for versioning and releases. If you haven't used Changesets before, here's the idea: instead of manually bumping version numbers, you describe what changed, and Changesets figures out the right version bump and generates a changelog for you. It's especially useful when you want a professional release workflow without the overhead.

Step 1 — Describe Your Changes

After you've made changes you want to release, run:

pnpm changeset

This opens an interactive prompt that asks you two things: what type of change this is (patch for bug fixes, minor for new features, major for breaking changes), and a short description of what changed. This description becomes part of your auto-generated changelog.

For example, if you fixed a timing issue with a scroll animation, you'd select "patch" and write something like "Fixed scroll animation firing before DOM ready."

Step 2 — Apply the Version Bump

pnpm changeset version

This reads your changeset, updates the version number in package.json accordingly, and writes the changelog entry. If you had version 1.0.0 and selected a patch bump, it becomes 1.0.1. Minor would make it 1.1.0, and major would make it 2.0.0.

You can review the changes before moving forward. Check your package.json to confirm the new version number, and look at the changelog to make sure the entry looks right.

Step 3 — Log In to npm

If this is your first time publishing, you need to authenticate with npm:

npm login
npm whoami

The login command opens a browser-based authentication flow. Once logged in, whoami should print your npm username to confirm you're authenticated. You only need to do this once per machine — npm remembers your session.

If you're publishing under an organization, make sure your npm account has publish access to that organization's scope.

Step 4 — Publish

pnpm release

This runs the production build and publishes the package to npm in one step. Once it completes, your package is live and available for anyone to install or load via CDN.

Make sure all your changes are committed before running this. The release command expects a clean working directory. If you have uncommitted changes, commit or stash them first.

Using on Webflow (or Any No-Code Platform)

This is the payoff. Once your package is published to npm, it's automatically available through the jsDelivr CDN — no extra configuration needed. jsDelivr mirrors the entire npm registry, so any published package can be loaded directly in a browser.

Generate your CDN links by running:

pnpm cdn

This reads your package.json and prints ready-to-use HTML tags that you can paste directly into your Webflow project. You'll get something like:

<script
  defer
  src="https://cdn.jsdelivr.net/npm/your-package@latest/dist/index.js"
></script>

For CSS files, it generates link tags instead:

<link
  rel="stylesheet"
  href="https://cdn.jsdelivr.net/npm/your-package@latest/dist/styles/global.css"
/>

In Webflow, go to your project settings, find the Custom Code section, and paste the script tag in the Footer Code area. For page-specific scripts, you can add them in the page settings instead of the project settings.

The @latest tag means your site will automatically use the newest published version. If you prefer to pin a specific version for stability (recommended for production), replace @latest with the exact version number like @1.0.0. This way, your live site won't break if you publish a change that has an unintended side effect.

This same approach works on any platform that lets you add custom HTML — Framer, Squarespace, Shopify, WordPress, or even plain HTML sites. If you can add a script tag, you can use CDN-Starter.

Project Structure

Here's a breakdown of every folder and file in your project, and what it does:

cdn-starter/
├── src/                 # Your source files — all your code goes here
│   ├── index.ts         # Main entry point
│   ├── styles/
│   │   └── global.css   # Global styles
│   └── home/
│       └── index.ts     # Page-specific scripts
├── bin/
│   └── build.js         # Entry point configuration
├── dist/                # Build output (auto-generated, do not edit)
├── .changeset/          # Changeset config and pending changesets
├── package.json         # Project metadata and scripts
├── tsconfig.json        # TypeScript configuration
├── eslint.config.js     # Linting rules
└── README.md

The src/ folder is where all your work happens. Organize it however makes sense for your project — by page, by feature, by component. The only rule is that any file you want compiled must be listed in bin/build.js.

The dist/ folder is entirely managed by the build system. It gets wiped and regenerated on every build. Never put anything in here manually.

The .changeset/ folder stores your pending changesets until you apply them. You generally don't need to interact with it directly.

Code Quality Tools

CDN-Starter ships with four commands for keeping your code clean. These are preconfigured and ready to use — no setup required.

pnpm lint

Runs ESLint across your source files and reports any issues — unused variables, type errors, formatting inconsistencies, and other common mistakes. It doesn't change any files, just tells you what's wrong.

pnpm lint:fix

Same as lint, but automatically fixes anything it can. Most formatting issues and simple code problems get resolved instantly. Anything it can't auto-fix will still be reported so you can handle it manually.

pnpm format

Runs Prettier to format all your files consistently. This handles indentation, line length, quote style, trailing commas, and all the other formatting decisions you don't want to think about. Run this before committing to keep your codebase clean.

pnpm check

Runs the TypeScript compiler in check mode. This catches type errors across your entire project without actually building anything. It's faster than a full build when you just want to verify your types are correct.

A good habit is to run pnpm check and pnpm lint before every commit. If you want to automate this, you can add a pre-commit hook with a tool like husky, but that's optional.

Troubleshooting

Build Fails or Behaves Unexpectedly

If something goes wrong during a build, the first thing to try is a clean install. Delete your node_modules folder and lock file, then reinstall:

rm -rf node_modules pnpm-lock.yaml
pnpm install

This resolves most issues caused by corrupted or mismatched dependencies.

TypeScript Errors

If you're seeing type errors that don't make sense, run a standalone type check:

pnpm check

This gives you clearer output than what you might see during a build. It also catches issues in files that aren't entry points — which the build step would otherwise skip.

npm Login or Publish Issues

If publishing fails, first verify you're logged in:

npm login
npm whoami

If whoami doesn't show your username, your session has expired and you need to log in again. Also make sure the package name in your package.json isn't already taken on npm by someone else. You can check by searching for it on npmjs.com.

Files Missing from Build Output

If a file you created isn't showing up in dist/, you almost certainly forgot to add it to the entry points array in bin/build.js. Open that file, add your new file's path, and run the build again.

Why I Built This

I was tired of reinventing the same setup every time I needed custom code on a Webflow project. Every project started the same way — install a bundler, configure TypeScript, figure out how to get a single output file, set up linting, and then fumble through the npm publishing process.

I wanted something that just works. Scaffold a project, write your code, publish it, paste a CDN link into Webflow, and move on. No configuration rabbit holes, no copy-pasting boilerplate from old projects, no second-guessing the build setup.

CDN-Starter is the tool I wish existed when I started building custom Webflow integrations. It's minimal, fast, and doesn't try to be more than what it needs to be. If it saves you even one hour of setup time, it's done its job.

GitHubXLinkedInInstagram

/RTSTIC