Setup
This guide shows how to set up Epos with Vite, TypeScript, and Tailwind CSS.
You can skip this guide and just select the Vite + TypeScript + Tailwind CSS template when creating a new project in the app.epos.dev dashboard. That sets up all the necessary configuration. If you want to understand how it works or customize the setup, read on.
1. Create a Vite Project
First, scaffold a fresh project with Vite:
npm create vite@latestpnpm create vitebun create viteyarn create viteFollow the prompts to set up the project:
- Project name: Choose any name for your project.
- Framework: Select Vanilla. Do not select React here, because Epos already provides it.
- Variant: Choose your preference. This guide assumes you select TypeScript.
2. Install Epos
Install the epos package:
npm install epospnpm add eposbun add eposyarn add eposThis package provides TypeScript types for the Epos API and includes the Epos Vite plugin.
3. Install Tailwind CSS
Install Tailwind CSS and its Vite plugin:
npm install -D tailwindcss @tailwindcss/vitepnpm add -D tailwindcss @tailwindcss/vitebun add -D tailwindcss @tailwindcss/viteyarn add -D tailwindcss @tailwindcss/vite4. Create vite.config.ts
Start with this config:
import tailwindcss from '@tailwindcss/vite'
import { epos } from 'epos/vite'
import { defineConfig } from 'vite'
export default defineConfig(({ mode }) => ({
plugins: [epos(), tailwindcss()],
build: {
watch: mode === 'production' ? null : {},
rolldownOptions: {
input: {
// Single entry point for now
main: './src/main.tsx',
},
output: {
// Avoid hashes in file names
entryFileNames: '[name].js',
assetFileNames: '[name].[ext]',
},
},
},
}))As you may know, Vite consists of two major parts:
- A dev server that serves your application on
localhost. - A build command that bundles your code into static output.
Epos works with actual built files, so we need to use the build command.
5. Update package.json
Update to use the build command:
{
...
"scripts": {
"dev": "vite --mode development",
"build": "tsc && vite build",
"preview": "vite preview"
"dev": "vite build --mode development",
"build": "vite build --mode production",
"preview": "vite build --mode preview"
},
...
}This uses Vite as a bundler that writes files into dist.
6. Add jsx to tsconfig.json
Add the jsx option to tsconfig.json to enable JSX syntax:
{
"compilerOptions": {
"jsx": "react-jsx",
...
},
"include": ["src"]
}7. Create the Entry Files
Remove the files that Vite created for the starter app:
src/*public/*index.html
Create src/main.tsx and src/main.css:
import 'epos'
import './main.css'
const App = () => {
return (
<div className="p-4 font-sans">
Epos + Vite
</div>
)
}
epos.render(<App />)@import 'tailwindcss';The import 'epos' line gives your editor types and autocomplete for the Epos API.
8. Create epos.json
Tell Epos to load the built files from dist.
{
"$schema": "https://epos.dev/schema.json",
"name": "My Extension",
"targets": [
{
"matches": "<popup>",
"load": ["dist/main.css", "dist/main.js"]
}
]
}Notice that epos.json points to bundled dist files, not src files.
9. Start the Build
Run the development build:
npm run devpnpm devbun devyarn devVite rebuilds your project whenever you change source files, and Epos picks up the updated dist output.
10. Multiple Entry Points
If your project has more than one entry point, add them all to input:
rolldownOptions: {
input: {
main: './src/main.tsx',
background: './src/background.ts',
},
}Then load the corresponding built files in epos.json:
"targets": [
{
"matches": "<popup>",
"load": ["dist/main.css", "dist/main.js"]
},
{
"matches": "<background>",
"load": ["dist/background.js"]
}
]11. Shared Chunks and vite-plugin-rebundle
With multiple entry points, Vite may extract shared code into extra chunk files. That is normally ok, but Epos cannot load those chunks directly because they are imported dynamically.
To avoid that, you can use vite-plugin-rebundle, which keeps a single output file per entry point:
npm install -D vite-plugin-rebundlepnpm add -D vite-plugin-rebundlebun add -D vite-plugin-rebundleyarn add -D vite-plugin-rebundleUpdate vite.config.ts:
import tailwindcss from '@tailwindcss/vite'
import { epos } from 'epos/vite'
import { defineConfig } from 'vite'
import { rebundle } from 'vite-plugin-rebundle'
export default defineConfig(({ mode }) => ({
plugins: [
epos(),
tailwindcss(),
rebundle({
output: {
minify: mode !== 'development',
},
}),
],
build: {
watch: mode === 'production' ? null : {},
minify: false,
rolldownOptions: {
input: {
main: './src/main.tsx',
background: './src/background.ts',
},
output: {
entryFileNames: '[name].js',
assetFileNames: '[name].[ext]',
},
},
},
}))Notice that minify is disabled for the normal Vite output and enabled for vite-plugin-rebundle. This way the files are minified only once, during rebundling.