Documentation
import/export
Share code between scripts using ES6-style named imports and exports.
Importing and Exporting
PixelScript uses ES6-style module imports and exports to share code between scripts.
Use exports to make functions, classes, and values available to other scripts, and imports to use them.
Note: Default exports are not supported. All exports must be named exports.
Exporting from Scripts
Export functions with export function
Make functions available to other scripts by prefixing them with export.
// utils/messages.js export function success(message) { return `§a✓ §f${message}`; } export function error(message) { return `§c✗ §f${message}`; } export function info(message) { return `§e§f${message}`; }
Export constants with export const
Export values and constants using export const.
// utils/constants.js export const SPAWN_WORLD = "world"; export const SPAWN_X = 0; export const SPAWN_Y = 64; export const SPAWN_Z = 0; export const MAX_PLAYERS = 100; export const SERVER_NAME = "PSCraft";
Export classes with export class
// utils/economy.js export class Economy { constructor() { this.accounts = new Map(); } getBalance(playerUUID) { return this.accounts.get(playerUUID) || 0; } setBalance(playerUUID, amount) { this.accounts.set(playerUUID, amount); } addMoney(playerUUID, amount) { const current = this.getBalance(playerUUID); this.setBalance(playerUUID, current + amount); } }
Importing Scripts
Import with import { name } from "path"
Load exported values from another script using import.
// features/welcome.js import { success, info } from '../utils/messages.js'; registerListener($.PlayerJoinEvent, (event) => { const player = event.getPlayer(); player.sendMessage(success("Welcome to the server!")); player.sendMessage(info("Type /help to get started")); });
Import multiple items
// features/teleport.js import { SPAWN_WORLD, SPAWN_X, SPAWN_Y, SPAWN_Z } from '../utils/constants.js'; function teleportToSpawn(player) { const location = newLocation(SPAWN_WORLD, SPAWN_X, SPAWN_Y, SPAWN_Z); player.teleport(location); }
Import classes
// features/shop.js import { Economy } from '../utils/economy.js'; const economy = new Economy(); registerCommand('balance', (sender) => { const uuid = sender.getUniqueId().toString(); const balance = economy.getBalance(uuid); sender.sendMessage(`§eYour balance: §a$${balance}`); });
Import Paths
Paths in import statements are relative to the current script file:
// scripts/features/economy/shop.js import { formatCurrency } from './currency.js'; // Same directory import { registerWarp } from '../warps/commands.js'; // Parent's sibling directory import { success, error } from '../../utils/messages. js'; // Two levels up, then down
All import paths must include the .js file extension.
Script Lifecycle with Imports
Imported scripts have special reload behavior:
Single Instance:
- An imported script only has one instance at runtime
- Multiple scripts importing the same module share that single instance
Reload Cascade:
- When an imported script is modified, it reloads
- All scripts that import it also reload
- Their children reload as well, creating a reload cascade
Shared Dependencies:
- If two scripts import the same utility, they share it
- Changes to that utility affect all importers simultaneously
// utils/database.js - Imported by many scripts let connectionPool = null; export function getConnection() { if (!connectionPool) { connectionPool = createPool(); } return connectionPool; } // This instance is shared by all scripts that import it // If database.js changes, ALL scripts importing it will reload
Practical Examples
Shared utility library
// utils/player_utils.js export function isAdmin(player) { return player.hasPermission('server.admin'); } export function isModerator(player) { return player.hasPermission('server.moderator'); } export function hasVIP(player) { return player.hasPermission('server.vip'); } export function sendActionBar(player, message) { player.sendActionBar(message); }
// features/admin_commands.js import { isAdmin } from '../utils/player_utils. js'; registerCommand('announce', (sender, args) => { if (!isAdmin(sender)) { sender.sendMessage("§cYou don't have permission!"); return; } const message = args. join(' '); Bukkit.broadcastMessage(`§6[ADMIN] §f${message}`); });
Database wrapper
// utils/database.js export function savePlayerData(uuid, data, callback) { Scheduler.runAsync(() => { Sql.makeUpdate( "UPDATE player_data SET data = ? WHERE uuid = ?", (stmt) => { stmt. setString(1, JSON.stringify(data)); stmt.setString(2, uuid); }, callback ); }); } export function loadPlayerData(uuid, callback) { Scheduler.runAsync(() => { Sql.makeQuery( "SELECT data FROM player_data WHERE uuid = ?", (stmt) => stmt.setString(1, uuid), (rs) => { if (rs !== null && rs.next()) { const data = JSON.parse(rs.getString("data")); Scheduler.runSync(() => callback(data)); } else { Scheduler.runSync(() => callback(null)); } } ); }); }
// features/player_stats.js import { loadPlayerData } from '../utils/database.js'; registerListener($.PlayerJoinEvent, (event) => { const player = event.getPlayer(); const uuid = player.getUniqueId().toString(); loadPlayerData(uuid, (data) => { if (data) { player.sendMessage(`Welcome back! Level: ${data.level}`); } else { player. sendMessage("Welcome new player!"); } }); });
Configuration manager
// utils/config.js const config = { spawn: { world: "world", x: 0, y: 64, z: 0 }, messages: { welcome: "§eWelcome to PSCraft! ", goodbye: "§eSee you soon!" }, features: { pvp: false, economy: true, warps: true } }; export function get(path) { const parts = path.split('.'); let value = config; for (const part of parts) { value = value[part]; if (value === undefined) { return null; } } return value; } export { config };
// features/spawn. js import { get } from '../utils/config.js'; registerCommand('spawn', (sender) => { const spawnConfig = get('spawn'); const location = newLocation( spawnConfig.world, spawnConfig.x, spawnConfig.y, spawnConfig.z ); sender.teleport(location); sender.sendMessage(get('messages.welcome')); });
Singleton pattern
// utils/economy.js class EconomyManager { constructor() { this.accounts = new Map(); } getBalance(playerUUID) { return this.accounts. get(playerUUID) || 0; } setBalance(playerUUID, amount) { this.accounts.set(playerUUID, amount); } addMoney(playerUUID, amount) { const current = this.getBalance(playerUUID); this.setBalance(playerUUID, current + amount); } removeMoney(playerUUID, amount) { const current = this.getBalance(playerUUID); if (current >= amount) { this.setBalance(playerUUID, current - amount); return true; } return false; } } // Export a singleton instance export const economy = new EconomyManager();
// features/shop.js import { economy } from '../utils/economy.js'; registerCommand('balance', (sender) => { const uuid = sender. getUniqueId().toString(); const balance = economy.getBalance(uuid); sender.sendMessage(`§eYour balance: §a$${balance}`); }); registerCommand('pay', (sender, args) => { if (args.length < 2) { sender.sendMessage("§cUsage: /pay <player> <amount>"); return; } const target = Bukkit.getPlayer(args[0]); const amount = parseInt(args[1]); if (!target) { sender.sendMessage("§cPlayer not found"); return; } const senderUUID = sender.getUniqueId().toString(); const targetUUID = target.getUniqueId().toString(); if (economy.removeMoney(senderUUID, amount)) { economy.addMoney(targetUUID, amount); sender.sendMessage(`§aYou paid §e$${amount} §ato ${target.getName()}`); target.sendMessage(`§aYou received §e$${amount} §afrom ${sender.getName()}`); } else { sender.sendMessage("§cInsufficient funds"); } });
Type-like interfaces with constants
// utils/types.js export const PlayerRank = { MEMBER: 'member', VIP: 'vip', MODERATOR: 'moderator', ADMIN: 'admin' }; export const GameState = { WAITING: 'waiting', STARTING: 'starting', ACTIVE: 'active', ENDING: 'ending' }; export const MessageType = { SUCCESS: 'success', ERROR: 'error', INFO: 'info', WARNING: 'warning' };
// features/minigame.js import { GameState } from '../utils/types.js'; let currentState = GameState.WAITING; function startGame() { if (currentState !== GameState.WAITING) { return; } currentState = GameState. STARTING; // Start countdown... }
Avoiding Reload Cascades
Be mindful of import dependencies to avoid unnecessary reloads:
// BAD: Utility imported by 50 scripts // utils/common.js - Changes here reload 50 scripts! export function utilityA() { } export function utilityB() { } export function utilityC() { } // ... 100 more utilities // GOOD: Split into focused modules // utils/messages.js - Only reloads scripts using messages // utils/permissions.js - Only reloads scripts using permissions // utils/formatting.js - Only reloads scripts using formatting
Best Practices
DO:
- Use named exports for all exports
- Group related utilities into focused modules
- Keep imported modules small and focused
- Use relative paths with
.jsextension - Export singleton instances for shared state
- Import only what you need
DON'T:
- Use default exports (not supported)
- Create circular dependencies (A imports B, B imports A)
- Put everything in one giant utility file
- Import modules inside frequently-called functions
- Forget that changes cascade to all importers
- Omit the
.jsfile extension
Watched vs Imported Scripts
Understanding the difference helps organize your codebase:
Watched scripts:
- Loaded via
Watcher. watch() - Act as reload barriers
- Don't reload when parent reloads
- Good for features and subsystems
Imported scripts:
- Loaded via
importstatements - Reload cascades to importers
- Good for utilities and shared code
// main.js // Watched: Won't reload when main.js reloads Watcher.watch('features/economy/init.js'); // Imported: Will cause main.js to reload if it changes import { SERVER_NAME } from './utils/config.js';
Import Resolution
PixelScript resolves imports relative to the current file:
// scripts/features/economy/shop.js import { formatCurrency } from './utils. js'; // Resolves to: scripts/features/economy/utils.js import { success } from '../../utils/messages.js'; // Resolves to: scripts/utils/messages.js import { SPAWN_X } from '../../../config.js'; // Resolves to: scripts/config.js
Always use relative paths starting with ./ or ../ and include the .js extension.
Parse and serialize JSON data for storage, API communication, and data interchange.
Stay updated with the latest changes and improvements in PixelScript through our detailed changelog.