Getting Started
- Project Structure
- Understanding Package.json
- NPM Scripts: Your Command Toolbox
- Managing Dependencies with Bakery
- Next Steps
Let's get you set up with Vite! This guide will walk you through the configuration, explain how assets are organized, and help you establish a smooth development workflow. Don't worry if some concepts are new—we'll explain everything as we go.
Project Structure
UserFrosting organizes assets in a standard structure:
your-project/
├── app/
│ └── assets/ # Source assets
│ ├── main.ts # Main entry point
│ ├── App.vue # Root Vue component
│ ├── theme.less # Custom styles
│ ├── router/ # Vue Router configuration
│ ├── components/ # Vue components
│ └── public/ # Static assets (copied as-is)
├── public/
│ └── assets/ # Compiled output (generated)
│ ├── main-[hash].js
│ ├── main-[hash].css
│ └── .vite/
│ └── manifest.json # Build manifest
├── vite.config.ts # Vite configuration
└── package.json # npm dependencies
Understanding Package.json
The package.json file is the heart of any Node.js project, including UserFrosting's frontend asset management. Think of it as the instruction manual and blueprint for your project—it tells NPM (Node Package Manager) what your project needs, how to build it, and how to run various tasks.
Tip
The package.json file is to JavaScript projects what composer.json is to PHP projects—it manages external dependencies and defines how to work with your project.
What is Package.json?
According to the official NPM documentation, package.json is a JSON file that serves multiple critical purposes:
- Dependency Management - Lists all external packages (libraries) your project needs
- Project Metadata - Defines your project's name, version, description, and author
- Script Automation - Contains commands for building, testing, and running your application
- Version Control - Specifies exact or acceptable versions of each dependency
- Configuration - Stores settings for various tools and build processes
Package.json and NPM
NPM (Node Package Manager) is the default package manager for Node.js and the world's largest software registry. When you install NPM packages, the registry at npmjs.com hosts millions of open-source packages that developers can use in their projects.
Here's how package.json and NPM work together:
- Installation - When you run
npm install, NPM readspackage.jsonto determine which packages to download - Version Resolution - NPM checks the version constraints (like
^3.4.0) and installs compatible versions - Dependency Tree - NPM automatically installs each package's dependencies, creating a
node_modulesfolder - Lock File - NPM generates
package-lock.jsonto ensure everyone installs identical versions
Note
The package-lock.json file is automatically generated and should be committed to version control. It locks exact versions of all dependencies, ensuring consistent installations across different environments. Learn more about package-lock.json.
UserFrosting's Package.json
UserFrosting's Skeleton template includes a pre-configured package.json with everything you need to get started. You don't need to create this file from scratch—it's already set up with sensible defaults for Vite, Vue 3, TypeScript, and all necessary build tools.
However, you can and should customize it to fit your project's needs:
- Add new dependencies for features you need (e.g., date pickers, charts, UI components)
- Remove unused dependencies to reduce bundle size
- Update versions to get bug fixes and new features
- Add custom scripts for your specific workflows
- Modify existing scripts to change build behavior
For example, if your project needs a date picker library, you would add it:
npm install --save flatpickr
This automatically updates your package.json with the new dependency:
{
"dependencies": {
"flatpickr": "^4.6.13"
}
}
Package.json Structure
Your package.json includes several key sections. Let's break down a typical UserFrosting configuration:
{
"name": "userfrosting-app",
"version": "1.0.0",
"type": "module",
"scripts": {
"vite:dev": "vite",
"vite:build": "vite build",
"typecheck": "vue-tsc --noEmit",
"lint": "eslint . --fix",
"test": "vitest",
"coverage": "vitest --coverage"
},
"dependencies": {
"vue": "^3.4.0",
"vue-router": "^4.3.0",
"axios": "^1.6.0",
"pinia": "^2.1.0",
"pinia-plugin-persistedstate": "^3.2.0",
"uikit": "^3.21.0"
},
"devDependencies": {
"@vitejs/plugin-vue": "^5.1.0",
"@modyfi/vite-plugin-yaml": "^1.1.0",
"vite": "^5.4.0",
"vite-plugin-vue-devtools": "^7.3.0",
"typescript": "^5.5.0",
"vue-tsc": "^2.0.0",
"@types/node": "^20.14.0",
"vitest": "^2.0.0",
"eslint": "^9.6.0"
}
}
Project Metadata
name- Your project's identifier (used for publishing to NPM if public)version- Current version following SemVer format (MAJOR.MINOR.PATCH)type- Set to"module"to enable ES modules (import/export syntax)
Dependencies vs DevDependencies
Understanding the difference between these two sections is important:
dependencies - Packages required for your application to run in production. These are installed in all environments and included in your final build:
vue- The Vue 3 framework for building reactive user interfacesvue-router- Official routing library for Vue.js single-page applicationsaxios- Promise-based HTTP client for making API requestspinia- Official state management library for Vue 3 (replaces Vuex)pinia-plugin-persistedstate- Persists Pinia state to localStorageuikit- Frontend CSS framework for styling components
devDependencies - Packages only needed during development and building. These are not included in production bundles:
@vitejs/plugin-vue- Vite plugin that compiles Vue Single File Components@modyfi/vite-plugin-yaml- Allows importing YAML files as JavaScript modulesvite- The build tool itselfvite-plugin-vue-devtools- Integrates Vue DevTools for debuggingtypescript- TypeScript compiler for type-safe JavaScriptvue-tsc- TypeScript type-checker specifically for Vue components@types/node- TypeScript type definitions for Node.js APIsvitest- Fast unit testing framework powered by Viteeslint- JavaScript/TypeScript linter for code quality
Tip
When installing new packages, use npm install --save (for dependencies) or npm install --save-dev (for devDependencies). The --save flag is now default in modern NPM versions, so npm install package-name adds to dependencies.
NPM Scripts: Your Command Toolbox
The scripts section in package.json is one of its most powerful features. Scripts are custom commands that automate common tasks—think of them as shortcuts that save you from typing long, complex commands.
NPM scripts are shell commands defined in your package.json that you can run using npm run <script-name>. They provide a standardized way to execute tasks across different projects and teams. According to the NPM scripts documentation, scripts can:
- Run command-line tools installed in
node_modules/.bin/ - Chain multiple commands together
- Pass arguments and environment variables
- Execute in a cross-platform compatible way
Why Use Scripts?
Instead of remembering complex commands like:
./node_modules/.bin/vite build --mode production --config vite.config.ts
You can simply run:
npm run vite:build
This makes your workflow:
- Consistent - Everyone uses the same commands
- Documented - New team members can see available commands
- Portable - Works across different operating systems
- Maintainable - Update the command once, affects everyone
UserFrosting's Script Commands
Let's explore each script in detail:
Development Scripts
npm run vite:dev - Starts the Vite development server
"vite:dev": "vite"
This launches Vite in development mode with:
- Hot Module Replacement (HMR) - Updates your browser instantly when you save files
- Fast refresh - Preserves component state during updates
- Source maps - Makes debugging easier by mapping compiled code to source
- Development server - Runs on
http://localhost:5173(by default)
When running, your browser loads assets directly from Vite's dev server for the fastest possible feedback loop.
npm run vite:build - Creates an optimized production build
"vite:build": "vite build"
This generates production-ready assets with:
- Code minification - Removes whitespace and shortens variable names
- Tree shaking - Eliminates unused code from bundles
- Asset optimization - Compresses images and files
- Code splitting - Breaks code into smaller chunks for faster loading
- Cache busting - Adds hashes to filenames (e.g.,
main-a1b2c3d4.js)
Output goes to public/assets/ and includes a manifest file for UserFrosting to reference assets.
Quality Assurance Scripts
npm run typecheck - Type-checks TypeScript without compilation
"typecheck": "vue-tsc --noEmit"
Runs the Vue TypeScript compiler to catch type errors before runtime. The --noEmit flag means it only checks types without generating JavaScript files (Vite handles compilation). This helps catch bugs like:
- Calling functions with wrong argument types
- Accessing undefined properties
- Mismatched component props
npm run lint - Runs ESLint and automatically fixes issues
"lint": "eslint . --fix"
ESLint analyzes your code for problems and enforces style guidelines. The --fix flag automatically corrects issues like:
- Inconsistent indentation and spacing
- Missing semicolons or trailing commas
- Unused variables
- Code complexity warnings
This keeps your codebase clean and consistent across the team.
Testing Scripts
npm run test - Runs Vitest unit tests
"test": "vitest"
Executes your test suite using Vitest, a blazing-fast testing framework. Tests ensure your components and functions work correctly and help prevent regressions when making changes.
npm run coverage - Generates test coverage report
"coverage": "vitest --coverage"
Creates a detailed report showing which parts of your code are tested. Coverage reports help identify untested code paths and improve test quality.
Running Scripts
To execute any script, use npm run followed by the script name:
# Development
npm run vite:dev
# Production build
npm run vite:build
# Quality checks
npm run typecheck
npm run lint
# Testing
npm run test
npm run coverage
Some scripts support additional arguments. For example, to run tests in watch mode:
npm run test -- --watch
The -- separator tells NPM to pass everything after it directly to the underlying command.
Creating Custom Scripts
You can add your own scripts for project-specific tasks. For example, you might add:
{
"scripts": {
"dev": "npm run vite:dev",
"build": "npm run typecheck && npm run vite:build",
"deploy": "npm run build && rsync -av public/ user@server:/var/www/",
"clean": "rm -rf public/assets node_modules"
}
}
dev- Shorter alias for starting developmentbuild- Type-check before building (catches errors early)deploy- Build and upload to server (automate deployment)clean- Remove generated files (useful for troubleshooting)
Tip
Use && to chain commands sequentially (second command runs only if first succeeds) or & to run commands in parallel. For cross-platform compatibility, consider using tools like npm-run-all for complex script orchestration.
Managing Dependencies with Bakery
While you can run NPM commands directly, UserFrosting provides convenient Bakery commands that wrap NPM functionality and integrate with your UserFrosting workflow. Think of these as UserFrosting's way of helping you manage frontend dependencies without leaving the PHP environment.
Installing Dependencies
To install all dependencies listed in your package.json:
php bakery assets:install
What it does:
- Runs
npm installto install dependencies - Installs exact versions from
package-lock.json - Validates Node.js and NPM versions
- Ensures your
node_modulesfolder is up to date
When to use:
- After cloning the repository
- After pulling changes that modify
package.json - When
node_modules/is missing or corrupted - As part of your deployment process
This is equivalent to running npm install directly, but provides additional validation and integrates with UserFrosting's environment checks.
Updating Dependencies
To update dependencies to their latest compatible versions:
php bakery assets:update
What it does:
- Runs
npm updateto update packages - Updates packages within the semver ranges specified in
package.json - Updates
package-lock.jsonwith new versions - Preserves your specified version constraints
For example, if your package.json specifies "vue": "^3.4.0", running assets:update might update to 3.5.2 (a newer minor version), but won't update to 4.0.0 (a new major version).
When to use:
- Regularly to get bug fixes and security patches
- After modifying version ranges in
package.json - Before starting work on a feature to ensure latest compatible versions
Warning
Running assets:update may introduce breaking changes if packages don't follow semantic versioning strictly. Always test thoroughly after updating dependencies, especially before deploying to production.
NPM vs Bakery Commands
You can use either NPM commands or Bakery commands—they accomplish the same goals:
| Task | NPM Command | Bakery Command |
|---|---|---|
| Install dependencies | npm install |
php bakery assets:install |
| Update dependencies | npm update |
php bakery assets:update |
| Run dev server | npm run vite:dev |
php bakery assets:vite |
| Build for production | npm run vite:build |
php bakery assets:vite --production |
When to use Bakery commands:
- You prefer working in the PHP environment
- You're already using Bakery for other tasks
- You want integrated validation and error messages
- You're automating with PHP scripts
When to use NPM directly:
- You're more comfortable with Node.js tools
- You need to pass complex arguments
- You're using package-specific features
- You're working primarily on frontend code
Next Steps
Now that you understand package.json, NPM scripts, and dependency management, learn about Vite Configuration to customize how assets are built and served.