Migration Guide
This appendix helps you upgrade LARC applications across versions, navigate breaking changes, and adopt new features while maintaining stability. Whether you're moving from an early prototype to a production release or keeping pace with framework evolution, this guide provides version-specific migration paths and practical strategies.
General Migration Strategy
Before diving into version-specific changes, establish a methodical upgrade process:
1. Review the Changelog Start with LARC's release notes. Note breaking changes, deprecations, and new features relevant to your application. 2. Update in Increments Avoid jumping multiple major versions. Upgrade one major version at a time, testing thoroughly between steps. 3. Run Your Test Suite Execute all tests before and after migration. Pay special attention to component integration tests that exercise PAN bus communication. 4. Check Dependencies Ensure your LARC-compatible libraries (routing, state management) support the new version. Update these incrementally. 5. Use Feature Flags When migrating large applications, use feature flags to toggle between old and new implementations during transition periods.Version 0.x to 1.0 Migration
The move to LARC 1.0 established core APIs and stabilized component architecture. Key changes:
Component Registration Changes
Before (0.x):LARC.register('my-widget', {
template: '<div>Content</div>',
props: ['data']
});
After (1.0):
class MyWidget extends HTMLElement {
static observedAttributes = ['data'];
connectedCallback() {
this.render();
}
render() {
this.innerHTML = '<div>Content</div>';
}
}
customElements.define('my-widget', MyWidget);
Migration Steps:
HTMLElementobservedAttributes for reactive propertiesrender() methodsPAN Bus API Refinement
Version 1.0 introduced explicit bus references rather than implicit global access.
Before (0.x):this.emit('data-changed', { value: 42 });
this.on('user-action', handler);
After (1.0):
this.pan.dispatch('data-changed', { value: 42 });
this.pan.subscribe('user-action', handler);
Migration Steps:
emit() with pan.dispatch()on() with pan.subscribe()Attribute Handling
Attribute parsing became more strict in 1.0.
Before (0.x):// Automatic JSON parsing
this.getAttribute('config'); // returns object
After (1.0):
// Explicit parsing required
JSON.parse(this.getAttribute('config') || '{}');
Migration Steps:
attributeChangedCallback() for reactive updatesobservedAttributes to declare monitored attributesVersion 1.x to 2.0 Migration
LARC 2.0 introduced TypeScript support, improved developer experience, and performance optimizations.
TypeScript Integration
While JavaScript remains fully supported, TypeScript brings type safety.
Migration Steps:npm install --save-dev @larc/types.js files to .ts incrementallyimport { PANEvent } from '@larc/core';
interface UserData {
id: string;
name: string;
}
class UserCard extends HTMLElement {
private userData: UserData | null = null;
connectedCallback() {
this.pan.subscribe<UserData>('user-selected', (event: PANEvent<UserData>) => {
this.userData = event.detail;
this.render();
});
}
}
Shadow DOM Adoption
Version 2.0 encouraged Shadow DOM for style encapsulation.
Before (1.x):connectedCallback() {
this.innerHTML = '<div class="container">Content</div>';
}
After (2.0):
connectedCallback() {
this.attachShadow({ mode: 'open' });
this.shadowRoot.innerHTML = `
<style>
.container { padding: 1rem; }
</style>
<div class="container">Content</div>
`;
}
Migration Considerations:
- Global styles won't penetrate Shadow DOM
- Use CSS custom properties for theming
- Update selectors in tests to query shadow roots
- Consider performance impact for large component trees
Async Component Initialization
Version 2.0 added first-class async support.
Before (1.x):connectedCallback() {
fetch('/api/data').then(data => {
this.data = data;
this.render();
});
}
After (2.0):
async connectedCallback() {
await this.initialize();
}
async initialize() {
try {
this.data = await fetch('/api/data').then(r => r.json());
this.render();
} catch (error) {
this.renderError(error);
}
}
Version 2.x to 3.0 Migration
LARC 3.0 focused on performance, introducing reactive primitives and optimized rendering.
Reactive State Management
The new reactive state system replaces manual render() calls.
class Counter extends HTMLElement {
constructor() {
super();
this.count = 0;
}
increment() {
this.count++;
this.render();
}
}
After (3.0):
import { reactive } from '@larc/core';
class Counter extends HTMLElement {
constructor() {
super();
this.state = reactive({ count: 0 });
this.state.$watch(() => this.render());
}
increment() {
this.state.count++; // automatically triggers render
}
}
Migration Steps:
reactive()$watch() for automatic renderingrender() calls after state changes$batch() for multiple simultaneous updatesPAN Bus Namespacing
Version 3.0 introduced event namespacing for better organization.
Before (2.x):this.pan.dispatch('data-loaded', data);
this.pan.dispatch('data-error', error);
this.pan.dispatch('data-cleared');
After (3.0):
this.pan.dispatch('data:loaded', data);
this.pan.dispatch('data:error', error);
this.pan.dispatch('data:cleared');
// Subscribe to namespace
this.pan.subscribe('data:*', (event) => {
console.log(`Data event: ${event.type}`);
});
Performance Optimizations
Version 3.0 added batched updates and render scheduling.
Manual Batching:import { batch } from '@larc/core';
batch(() => {
this.state.count++;
this.state.name = 'Updated';
this.state.timestamp = Date.now();
}); // Single render after all changes
Render Scheduling:
class HeavyComponent extends HTMLElement {
render() {
requestIdleCallback(() => {
// Expensive rendering during idle time
this.updateComplexUI();
});
}
}
Deprecation Timeline
Currently Deprecated (Remove in 4.0)
Legacy Event Syntax:// Deprecated
this.pan.on('event-name', handler);
// Use instead
this.pan.subscribe('event-name', handler);
Global Bus Access:
// Deprecated
window.PAN.dispatch('event');
// Use instead
this.pan.dispatch('event');
Synchronous connectedCallback with async operations:
// Deprecated pattern
connectedCallback() {
fetch('/data').then(d => this.data = d);
this.render(); // Renders before data loads
}
// Preferred
async connectedCallback() {
this.data = await fetch('/data').then(r => r.json());
this.render();
}
Planned Deprecations (4.0+)
- Direct innerHTML manipulation (prefer template literals or JSX)
- Imperative event listener registration (favor declarative templates)
- String-based event names (transition to strongly-typed event enums)
Breaking Changes Checklist
When upgrading major versions, verify these common breaking change areas:
API Surface:- [ ] Component registration method
- [ ] PAN bus method names
- [ ] Event payload structure
- [ ] Lifecycle callback signatures
- [ ] Attribute parsing (automatic vs. manual)
- [ ] Default Shadow DOM usage
- [ ] Event bubbling and cancellation
- [ ] Async initialization timing
- [ ] Bundler configuration
- [ ] TypeScript compiler options
- [ ] Test framework compatibility
- [ ] Development server setup
- [ ] Peer dependency versions
- [ ] Polyfill requirements
- [ ] Browser compatibility targets
- [ ] Third-party library compatibility
Migration Tools
Automated Refactoring
Use these tools to accelerate migration:
AST-Based Transforms:npx @larc/migrate --from 2.x --to 3.0 src/**/*.js
Codemod Scripts:
// Example: Convert emit to dispatch
module.exports = function(fileInfo, api) {
const j = api.jscodeshift;
return j(fileInfo.source)
.find(j.CallExpression, {
callee: {
object: { type: 'ThisExpression' },
property: { name: 'emit' }
}
})
.forEach(path => {
path.value.callee.property.name = 'dispatch';
})
.toSource();
};
Manual Review Points
Automated tools can't catch everything. Manually review:
Rollback Strategy
If migration causes critical issues:
Getting Help
When stuck during migration:
- Documentation: Check version-specific upgrade guides at larc.dev/migrate
- Community: Ask in GitHub Discussions or Discord
- Issue Tracker: Search for similar migration problems
- Support Contracts: Enterprise users can access dedicated migration assistance