Building for Platform
This guide covers how to build and prepare your plugin for deployment to the GxP platform.
Build Command
Run the build command to create a production-ready bundle:
gxdev build
# or
npm run build
This creates a dist/ folder with optimized assets:
dist/
├── assets/
│ ├── Plugin-[hash].js # Main plugin bundle
│ ├── Plugin-[hash].css # Extracted styles
│ └── [other chunks] # Code-split chunks
├── index.html # (dev only, not deployed)
└── manifest.json # Build manifest
What Gets Built
The build process:
- Compiles Vue SFCs - Single File Components are compiled to JavaScript
- Bundles dependencies - Tree-shakes and bundles only what you use
- Extracts CSS - Styles are extracted to separate files
- Minifies code - JavaScript and CSS are minified
- Generates hashes - File names include content hashes for caching
- Creates source maps - Optional source maps for debugging
Build Configuration
vite.config.js
Your project's vite.config.js controls the build:
import { defineConfig } from "vite"
import vue from "@vitejs/plugin-vue"
import path from "path"
export default defineConfig({
plugins: [vue()],
resolve: {
alias: {
"@": path.resolve(__dirname, "./src"),
"@layouts": path.resolve(__dirname, "./theme-layouts"),
"@gx-runtime": path.resolve(
__dirname,
"./node_modules/@gxp-dev/tools/runtime",
),
},
},
build: {
lib: {
entry: path.resolve(__dirname, "src/Plugin.vue"),
name: "GxpPlugin",
fileName: (format) => `plugin.${format}.js`,
},
rollupOptions: {
external: ["vue", "pinia"],
output: {
globals: {
vue: "Vue",
pinia: "Pinia",
},
},
},
},
})
Environment Variables
Production builds use .env.production if present:
# .env.production
VITE_API_URL=https://api.gramercy.cloud
VITE_ENVIRONMENT=production
Access in code:
const apiUrl = import.meta.env.VITE_API_URL
Pre-Build Checklist
Before building for production:
1. Remove Development Code
// Remove or wrap in dev checks
if (import.meta.env.DEV) {
console.log("Debug info:", data)
}
2. Verify All Strings Are Extracted
Run the string scanner to find hardcoded text:
gxdev datastore scan-strings
Ensure all user-facing text uses gxp-string directives.
3. Check Asset References
Verify all assets use gxp-src directives:
<!-- Good -->
<img gxp-src="hero_image" src="/dev-assets/placeholder.jpg" />
<!-- Bad - hardcoded URL won't work in production -->
<img src="/dev-assets/images/hero.jpg" />
4. Test All Layouts
Test your plugin in all layout contexts:
- Public layout
- Private layout
- System layout
Use the Dev Tools layout switcher or:
window.gxDevTools.setLayout("public")
window.gxDevTools.setLayout("private")
window.gxDevTools.setLayout("system")
5. Validate Manifest
Ensure your app-manifest.json is complete:
# Check for JSON syntax errors
cat app-manifest.json | python -m json.tool
Production Considerations
Performance
- Lazy load routes - Use dynamic imports for large components
- Optimize images - Use appropriate sizes and formats
- Minimize dependencies - Only import what you need
// Lazy load heavy components
const HeavyChart = defineAsyncComponent(
() => import("./components/HeavyChart.vue"),
)
Error Handling
Add proper error boundaries:
<template>
<div v-if="error" class="error-state">
<p gxp-string="error_generic">Something went wrong</p>
<button @click="retry">Retry</button>
</div>
<div v-else>
<!-- Normal content -->
</div>
</template>
Offline Support
Consider what happens when the network is unavailable:
const store = useGxpStore()
try {
const data = await store.apiGet("/endpoint")
} catch (error) {
if (!navigator.onLine) {
store.updateState("offline_mode", true)
}
}
Accessibility
Ensure your plugin is accessible:
- Use semantic HTML elements
- Add ARIA labels where needed
- Support keyboard navigation
- Test with screen readers
<button
gxp-string="btn_checkin"
aria-label="Check in to the event"
@keydown.enter="handleCheckin"
>
Check In
</button>
Deployment
Upload to Platform
After building, upload your plugin to the GxP platform:
- Log in to the GxP admin portal
- Navigate to Plugins > Upload
- Select your
dist/folder contents - Configure plugin settings
- Assign to kiosks
Version Management
Track your plugin versions:
// package.json
{
"name": "my-plugin",
"version": "1.2.0"
}
Use semantic versioning:
- MAJOR - Breaking changes
- MINOR - New features (backward compatible)
- PATCH - Bug fixes
Testing in Production
Use the browser extensions to test your plugin on production kiosks:
# Build extensions for distribution
gxdev ext:build
This creates installable extension packages for Chrome and Firefox.
Troubleshooting Builds
Build Fails with Import Errors
Check that all imports use the correct aliases:
// Correct
import { useGxpStore } from "@gx-runtime/stores/gxpPortalConfigStore"
// Wrong - path won't resolve in production
import { useGxpStore } from "../../node_modules/@gxp-dev/tools/runtime/stores/gxpPortalConfigStore"
CSS Not Loading
Ensure styles are properly scoped or imported:
<style scoped>
/* Scoped styles are extracted correctly */
.my-component {
color: blue;
}
</style>
Bundle Too Large
Analyze your bundle:
# Add to package.json scripts
"analyze": "vite build --mode analyze"
Check for:
- Unused dependencies
- Large libraries that could be lazy-loaded
- Duplicate code
Assets Not Found
Production assets come from the platform. Ensure you're using directives:
<!-- Platform provides the actual URL -->
<img gxp-src="logo" src="/placeholder.jpg" />
The src attribute is only used during development as a fallback.