Skip to main content
Version: v1 (Current)

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:

  1. Compiles Vue SFCs - Single File Components are compiled to JavaScript
  2. Bundles dependencies - Tree-shakes and bundles only what you use
  3. Extracts CSS - Styles are extracted to separate files
  4. Minifies code - JavaScript and CSS are minified
  5. Generates hashes - File names include content hashes for caching
  6. 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:

  1. Log in to the GxP admin portal
  2. Navigate to Plugins > Upload
  3. Select your dist/ folder contents
  4. Configure plugin settings
  5. 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.