Setting Up a Landing Page Project with Vite
Vite is a fantastic bundler

In recent years, the web development eco-system have made a massive breakthrough! Thanks to “Vite”, the fast and optimized web bundler, now we can scaffold and optimize all kinds of web project and assets. From full-fledged web applications using React, Vue, etc, to simple marketing landing pages.
Why Vite?
A bundler is a tool that takes all your code files - HTML, JavaScript, CSS, images, etc. - and combines them into optimized files that browsers can efficiently load. Traditional bundlers like Webpack and Parcel have to process your entire application before you can see any changes in development, which can become painfully slow as projects grow.
Vite is a bundler that takes a fundamentally different approach. Instead of bundling everything upfront during development, it leverages ES modules (the browser’s native module system) which means:
Lightning-fast cold starts: Traditional bundlers take up to 30-60 seconds to spin up on large projects. Vite starts in milliseconds, regardless of project size.
Instant Hot Module Replacement (HMR): Change your code and see changes in the browser instantly - no full page reloads, no waiting. Traditional bundlers have to rebuild affected chunks, which slows down as your app grows.
Powered by ESBuild: For production builds, Vite uses ESBuild (written in Go) for transpilation, which is 10-100x faster than Javascript-based bundlers.
For a single-page landing page site, Vite offers the perfect balance: simple configuration, modern defaults (Typescript and SCSS work out of the box), and professional build output with minification, code splitting, and cache-busting hashes - all without complex Webpack configs or plugin ecosystems to navigate. Let’s see how we can set this up.
Project Setup
Now that we understand why Vite is a great choice, let’s walk through setting up a production-ready landing page project from scratch. We’ll configure Typescript for type safety, SCSS for styling, and establish a clean project structure that’s both maintainable and scalable.
Prerequisites & Initial Setup
Before we begin, make sure you have nodejs version 18 or higher installed. You
can check your version from the command line.
node --version
First create your project directory and initialize it.
mkdir my-landingpage
cd my-landingpage
npm init -y
This creates a basic package.json file. Now install Vite as a development
dependency.
npm install -D vite
That’s it for the initial setup. Vite is now installed and ready to use. In the next steps, we’ll structure our project and add TypeScript and SCSS support.
Project Structure
One of the first decisions you’ll make is where to place your index.html file.
Vite’s default convention is to keep it in the project root, but you can also
place it inside src/ directory with some configuration.
Option 1: Root Level index.html (Vite’s default)
my-landingpage/
├── index.html # Entry point in root
├── src/
│ ├── scripts/
│ │ └── main.ts
│ └── styles/
│ └── main.scss
├── package.json
└── node_modules/
With this structure, your index.html references files like this.
<link rel="stylesheet" href="/src/styles/main.scss" />
<script type="module" src="/src/scripts/main.ts"></script>
Option 2: index.html inside src/ (requires config)
my-landingpage/
├── src/
│ ├── index.html # Entry point in src
│ ├── scripts/
│ │ └── main.ts
│ └── styles/
│ └── main.scss
├── vite.config.ts # Required for this setup
├── package.json
└── node_modules/
This approach keeps all source files together and requires a vite.config.ts
(we’ll cover this in section 2.6).
Regardless of which structure you choose, the mental model is the same. For this
guide, we’ll use Option 2 (everything in src/), as it keeps the project
root cleaner and separate source code from configuration files.
TypeScript Configuration
Vite has built-in TypeScript support, but we need to install TypeScript and create a configuration file. Install TypeScript as a development dependency.
npm install -D typescript
Create a tsconfig.json file in your project root.
{
"compilerOptions": {
"target": "ES2020",
"module": "ESNext",
"lib": ["ES2020", "DOM"],
"strict": true,
"moduleResolution": "node",
"esModuleInterop": true
},
"include": ["src/**/*"]
}
What these options mean:
target: "ES2020": Compiles TypeScript to ES2020 JavaScript, which all modern web browsers support.module: "ESNext": Uses the latest ES module syntax.lib: ["ES2020", "DOM"]: Provides type definitions for ES2020 features and browser DOM APIs.strict: true: Enables all strict type-checking options (catches more potential errors). This is an optional but recommended config.moduleResolution: "node": Resolves modules the way Node.js does.esModuleInterop: true: Allows default imports from CommonJS modules.include: ["src/**/*"]: Only compile files insidesrc/directory.
This configuration gives you strong type safety while maintaining compatibility with modern JavaScript features. Vite will automatically transpile your TypeScript files - no additional loaders or plugins required.
SCSS Setup
One of Vite’s best features is how effortlessly it handles CSS preprocessors.
For SCSS, you simply install the sass package, and Vite takes care of the rest
– no configuration needed. Install sass as a development dependency.
npm install -D sass
That’s it! Vite will automatically compile any .scss files you import. You can
now organize your styles like this.
src/styles/
├── main.scss # Main entry point
├── _variables.scss # SCSS variables
└── _mixins.scss # Reusable mixins
In your main.scss, import the partials.
// Variables and mixins
@use 'variables' as *;
@use 'mixins';
body {
margin: 0;
// rest of your code
}
Then reference it in your index.html like so.
<link rel="stylesheet" href="/styles/main.scss" />
Vite will compile the SCSS to CSS, minify it, and add cache-busting hashes in production builds automatically. No Webpack loaders, no complex configuration – just install Sass and start writing.
Package.json & Scripts
Now let’s configure our package.json with the necessary scripts and settings.
Open your package.json and make these changes.
{
"name": "my-landingpage",
"version": "1.0.0",
"description": "My Landing Page",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview"
},
"devDependencies": {
"sass": "^1.77.0",
"typescript": "^5.0.0",
"vite": "^5.0.0"
}
}
Key points:
type: "module": This is crucial. It tells Node.js to treat.jsfiles as ES modules, which aligns with Vite’s modern module approach. Without this, you may encounter module resolution errors.dev: "vite": Starts the Vite development server with hot module replacement. Your site will be available athttp://localhost:5173by default.build: "vite build": Creates an optimized production build in the dist/ directory with minification, tree-shaking, and code splitting.preview: "vite preview": Serves the production build locally so you can test it before deployment.
Vite Configuration
Vite works out of the box for most projects, so a configuration file is
optional. However, since we chose to place index.html inside the src/
directory, we need to tell Vite where to find it. Now create a vite.config.ts
file in your project root.
import { defineConfig } from 'vite';
import { resolve } from 'path';
export default defineConfig({
root: 'src',
build: {
outDir: '../dist',
emptyOutDir: true,
minify: 'terser', // Better compression (requires npm install -D terser)
sourcemap: false, // Disables sourcemaps in production
},
});
What these options mean:
root: "src": Tells Vite to look forindex.htmlinsidesrc/directory instead of the project root.outDir: "../dist": Since our root is nowsrc/, we need to point the output directory one level up to keepdist/in the project root.emptyOutDir: true: Clearsdist/directory before each build to remove stale files.
First Build
Let’s test our setup. First, create the basic files if you haven’t already.
src/index.html
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>My Landing Page</title>
<link rel="stylesheet" href="/styles/main.scss" />
</head>
<body>
<h1>Hello, Vite!</h1>
<script type="module" src="/scripts/main.ts"></script>
</body>
</html>
src/scripts/main.ts
console.log('Vite + TypeScript is working!');
src/styles/main.scss
body {
font-family: system-ui, sans-serif;
margin: 0;
padding: 2rem;
}
Then start the development server.
npm run dev
Open http://localhost:5173 in your browser. You should see your page with hot
module replacement enabled - any changes you save will instantly reflect in the
browser. Now let’s build for production.
npm run build
This creates a dist/ directory containing the following:
dist/
├── index.html
└── assets/
├── main-[hash].js
└── main-[hash].css
The output files are minified, tree-shaken, and includes cache-busting hashes. This is what you deploy to production. If you want to preview the production build you can run the following:
npm run preview
This serves dist/ directory locally so you can verify everything works before
deployment.
Final Thoughts
We’ve built a clean production-ready setup for a landing page using Vite, TypeScript, and SCSS. What we have now is a:
- A fast development environment with instant hot reloading
- Type-safe JavaScript with TypeScript
- Organized styling with SCSS
- Optimized production builds with minification and cache-busting
This setup hits a sweet spot for landing pages and simple sites. You get modern tooling and developer experience without the overhead of a full framework like React or Vue. Everything compiles down to vanilla HTML, CSS, and JavaScript - fast to load, easy to deploy anywhere.