diff --git a/content/guide/agentic-coding.md b/content/guide/agentic-coding.md new file mode 100644 index 00000000..803802fd --- /dev/null +++ b/content/guide/agentic-coding.md @@ -0,0 +1,271 @@ +--- +title: Agentic Coding +description: Leverage AI coding assistants to build higher quality NativeScript applications faster +contributors: + - NathanWalker +--- + +Agentic coding refers to using AI-powered coding assistants that can autonomously perform complex multi-step development tasks. These tools go beyond simple code completion; they can understand your entire codebase, make architectural decisions, write tests, and implement features end-to-end. + +## Why Agentic Coding for NativeScript? + +NativeScript's architecture provides the following: + +- **Direct native API access** - AI agents need to understand both JavaScript/TypeScript and native iOS/Android APIs +- **Cross-platform patterns** - Agents must generate code that works correctly on multiple platforms +- **Framework flexibility** - Code generation should adapt to Angular, Vue, Solid, Svelte, React, or plain TypeScript +- **Performance considerations** - Agents should follow best practices for native mobile performance + +By providing proper context, AI coding assistants can generate high-quality NativeScript code that follows best practices and leverages the full power of the platform. + +## The NATIVESCRIPT.md Context File + +NativeScript provides a comprehensive context file that can be used with any AI coding assistant to dramatically improve code generation quality. This file contains: + +- Project structure conventions +- Core API patterns and imports +- UI component reference +- Best practices for performance +- Platform-specific code patterns +- Framework integration examples +- Custom view creation patterns + +### Getting the Context File + +The `NATIVESCRIPT.md` file is available for download: + +**[Download NATIVESCRIPT.md](https://docs.nativescript.org/assets/agentic/NATIVESCRIPT.md)** + +You can also download it via the command line: + +```bash +curl -o CLAUDE.md https://docs.nativescript.org/assets/agentic/NATIVESCRIPT.md +``` + +## Using with Claude Code + +[Claude Code](https://code.claude.com) is Anthropic's agentic coding tool that runs in your terminal. It uses `CLAUDE.md` files to understand project context. + +### Setup + +1. Download the NativeScript context file to your project root: + +```bash +curl -o CLAUDE.md https://docs.nativescript.org/assets/agentic/NATIVESCRIPT.md +``` + +2. Optionally, add project-specific instructions at the top of the file: + +```markdown +# Project Context + +This is a NativeScript Vue 3 application for managing recipes. + +## Project-Specific Patterns +- We use Pinia for state management +- API calls go through `src/services/api.ts` +- All components are in `src/components/` + +--- + +# NativeScript AI Agent Context +... (rest of NATIVESCRIPT.md content) +``` + +3. Start Claude Code in your project: + +```bash +cd your-nativescript-project +claude +``` + +Claude will automatically read the `CLAUDE.md` file and use it to inform all code generation. + +### Example Prompts + +With the context file in place, you can give high-level instructions: + +``` +Create a settings page with switches for notifications, dark mode, and location tracking. +Save preferences using ApplicationSettings. +``` + +``` +Build a ListView that shows products with images, names, and prices. +Use template selectors for featured vs regular items. +``` + +``` +Create a custom native view that wraps Android's MaterialCardView and iOS's UIVisualEffectView. +``` + +## Using with Other AI Tools + +The `NATIVESCRIPT.md` context file works with any AI coding assistant that supports custom context: + +### GitHub Copilot + +Download and add to your workspace's `.github/copilot-instructions.md`: + +```bash +curl -o .github/copilot-instructions.md https://docs.nativescript.org/assets/agentic/NATIVESCRIPT.md +``` + +### Cursor + +Add to your `.cursorrules` file or include in your project's context settings. + +### Windsurf + +Add to your workspace's `.windsurfrules` file. + +### ChatGPT / Claude.ai Web + +Copy the relevant sections into your conversation as context before asking NativeScript-related questions. + +## Best Practices for AI-Assisted NativeScript Development + +### 1. Be Specific About Your Framework + +When prompting, specify which framework you're using: + +``` +Using NativeScript with Vue 3, create a component that... +``` + +``` +In my Angular NativeScript app, implement a service that... +``` + +``` +Using NativeScript with SolidJS, build a custom directive that... +``` + +``` +While using NativeScript with React, create a functional component that... +``` + +``` +Using NativeScript with Svelte, create a store that... +``` + +### 2. Reference Platform When Needed + +For platform-specific features, mention the target: + +``` +Create an iOS-specific implementation that uses UIBlurEffect. You can reference it here https://developer.apple.com/documentation/uikit/uiblureffect?language=objc +``` + +``` +Add Android haptic feedback using the native Vibrator API. You can reference it here https://developer.android.com/reference/android/os/Vibrator +``` + +### 3. Mention Performance Requirements + +Help the AI understand performance constraints: + +``` +This will be used in a ListView with 1000+ items, so optimize for scroll performance. +``` + +``` +This animation runs during user interaction, keep it on the UI thread. +``` + +### 4. Describe the User Experience + +Provide UX context for better implementations: + +``` +Create a pull-to-refresh list that shows a loading indicator while fetching new data. +``` + +``` +Build a form that validates on blur and shows inline error messages. +``` + +### 5. Request Tests When Appropriate + +``` +Create unit tests for the data transformation logic in this service. +``` + +## Extending the Context File + +For team projects, consider extending the base context file with project-specific information: + +### Create a Project-Specific Section + +```markdown +# Project: Recipe Manager App + +## Architecture +- Feature-based folder structure (`src/features/recipes/`, `src/features/auth/`) +- Shared components in `src/shared/components/` +- All API calls through `src/core/api/client.ts` + +## Conventions +- Use `const` for all variables unless reassignment is needed +- Prefer composition over inheritance +- All async operations use async/await (no raw promises) + +## State Management +- Pinia stores in `src/stores/` +- Each feature has its own store + +--- + +@CLAUDE.md +``` + +The `@` import syntax (supported in Claude Code) lets you reference the base file without duplicating its contents. Just ensure you've downloaded `NATIVESCRIPT.md` as `CLAUDE.md` in your project root. + +### Add Framework-Specific Rules + +If your team uses specific patterns, document them: + +```markdown +## Vue Component Patterns + +- Use ` + + + +``` + +### React +```tsx +const App = () => { + return ( + + + ) +} +``` + +## Configuration (nativescript.config.ts) + +```typescript +import { NativeScriptConfig } from '@nativescript/core' + +export default { + id: 'org.nativescript.myapp', + appPath: 'src', + appResourcesPath: 'App_Resources', + android: { + v8Flags: '--expose_gc', + markingMode: 'none', + }, + ios: { + // iOS-specific config + }, +} as NativeScriptConfig +``` + +## Security Configuration + +NativeScript includes security options to control sensitive runtime behaviors, particularly around remote ES module imports. + +### Remote Module Security + +NativeScript supports dynamic `import()` from remote URLs. This is useful during development but carries security implications in production since NativeScript code has **direct access to native platform APIs** (file system, keychain, network, camera, etc.). + +| Mode | Remote Modules | +|------|----------------| +| **Debug** | ✅ Always allowed | +| **Production** | ❌ Blocked by default | + +### Enabling Remote Modules in Production + +If you need remote ES modules in production, explicitly opt-in: + +```typescript +import { NativeScriptConfig } from '@nativescript/core' + +export default { + id: 'org.nativescript.myapp', + appPath: 'src', + + security: { + allowRemoteModules: true + } +} as NativeScriptConfig +``` + +### Using an Allowlist (Recommended) + +Restrict to specific trusted origins: + +```typescript +export default { + // ... + security: { + allowRemoteModules: true, + remoteModuleAllowlist: [ + 'https://cdn.yourcompany.com/modules/', + 'https://esm.sh/@yourorg/' + ] + } +} as NativeScriptConfig +``` + +The allowlist uses **prefix matching** — a URL is allowed if it starts with any entry. + +### Security Best Practices + +- **Keep production secure by default** - Don't enable unless necessary +- **Use narrow allowlists** - Specific paths, not broad domains +- **Pin versions in URLs** - Use immutable, versioned URLs +- **Never use user-controlled URLs** - Injection vulnerability risk + +For comprehensive security guidance, see the [Security Guide](/guide/security). + +## Common CLI Commands + +```bash +# Create new project +ns create myApp --template @nativescript/template-blank + +# Run on device/emulator +ns run android +ns run ios + +# Debug on device/emulator +ns debug android +ns debug ios + +# Disable HMR for standard live reload +ns debug android --no-hmr +ns debug ios --no-hmr + +# Build release +ns build android --release +ns build ios --release + +# Clean project (run after App_Resources changes) +ns clean + +# Add native code +ns native add swift MyClass +ns native add objective-c OtherAwesomeClass +ns native add kotlin com.example.MyClass +ns native add java com.company.OtherAwesomeClass +``` + +## Property System for Custom Views + +```typescript +import { Property, View } from '@nativescript/core' + +class MyView extends View { + // Define property with automatic native sync +} + +export const myProperty = new Property({ + name: 'myProperty', + defaultValue: '', + affectsLayout: true, +}) + +myProperty.register(MyView) +``` + +## Tracing and Error Handling + +The `Trace` module provides powerful debugging and error handling capabilities that go beyond `console.log`: + +- Control which categories of messages are logged +- Disable all tracing with a single call for production +- Create custom trace writers for specialized output +- Implement custom error handlers for crash reporting + +### Basic Tracing Setup + +```typescript +import { Trace } from '@nativescript/core' + +// 1. Set categories to trace (in app.ts) +Trace.setCategories(Trace.categories.concat('MyApp', 'MyApp.Network')) + +// 2. Enable tracing +Trace.enable() + +// 3. Write trace messages throughout your app +Trace.write('User logged in', 'MyApp', Trace.messageType.info) +Trace.write('API call failed', 'MyApp.Network', Trace.messageType.error) + +// 4. Disable in production +if (!__DEV__) { + Trace.disable() +} +``` + +### Built-in Trace Categories + +```typescript +Trace.categories.VisualTreeEvents // View lifecycle events +Trace.categories.Layout // Layout calculations +Trace.categories.Style // CSS/styling +Trace.categories.ViewHierarchy // View tree changes +Trace.categories.NativeLifecycle // Native platform lifecycle +Trace.categories.Navigation // Frame navigation +Trace.categories.Binding // Data binding +Trace.categories.BindingError // Data binding errors +Trace.categories.Error // General errors +Trace.categories.Animation // Animation events +Trace.categories.Transition // Page transitions +Trace.categories.All // All categories + +// Combine built-in with custom categories +Trace.setCategories(Trace.categories.concat('MyCategory1', 'MyCategory2')) +``` + +### Message Types + +```typescript +Trace.messageType.log // 0 - General log +Trace.messageType.info // 1 - Informational +Trace.messageType.warn // 2 - Warning +Trace.messageType.error // 3 - Error +``` + +### Custom Trace Writer + +Create custom writers to format output or send logs to external services: + +```typescript +import { Trace, TraceWriter } from '@nativescript/core' + +const TimestampTraceWriter: TraceWriter = { + write(message, category, type) { + const timestamp = new Date().toISOString() + const typeLabel = ['LOG', 'INFO', 'WARN', 'ERROR'][type] || 'LOG' + + console.log(`[${timestamp}] [${typeLabel}] [${category}] ${message}`) + + // Optional: Send to external logging service + if (type === Trace.messageType.error) { + sendToLogService({ timestamp, category, message, type }) + } + } +} + +// Replace default writers with custom writer +Trace.clearWriters() +Trace.addWriter(TimestampTraceWriter) +``` + +### Custom Error Handler + +Register a custom error handler for centralized error management: + +```typescript +import { Trace, TraceErrorHandler } from '@nativescript/core' + +const errorHandler: TraceErrorHandler = { + handlerError(err: Error) { + if (__DEV__) { + // Development: Log detailed error + Trace.write( + `${err.message}\n${err.stack}`, + 'unhandled-error', + Trace.messageType.error + ) + // Optionally re-throw to see in debugger + throw err + } else { + // Production: Report to analytics/crash reporting + reportToCrashlytics(err) + } + } +} + +// Register the error handler (in app.ts) +Trace.setErrorHandler(errorHandler) + +// Pass errors to the handler +try { + riskyOperation() +} catch (err) { + Trace.error(err) +} +``` + +### Global Application Error Events + +Handle uncaught errors and promise rejections: + +```typescript +import { Application } from '@nativescript/core' + +// Uncaught JavaScript errors +Application.on(Application.uncaughtErrorEvent, (args) => { + const error = args.error + console.error('Uncaught error:', error.message) + console.error('Stack:', error.stack) + + // Report to crash service + reportError(error) + + // Optionally prevent app crash (use with caution) + // args.cancel = true +}) + +// Unhandled promise rejections +Application.on(Application.discardedErrorEvent, (args) => { + console.error('Unhandled promise rejection:', args.error) + reportError(args.error) +}) +``` + +### Complete Error Handling Setup + +```typescript +// app.ts - Recommended error handling setup +import { Application, Trace, TraceErrorHandler } from '@nativescript/core' + +// 1. Setup trace categories +Trace.setCategories(Trace.categories.concat('App', 'App.Error')) + +// 2. Enable tracing in development +if (__DEV__) { + Trace.enable() +} + +// 3. Custom error handler +const errorHandler: TraceErrorHandler = { + handlerError(err: Error) { + Trace.write(err.message, 'App.Error', Trace.messageType.error) + + if (!__DEV__) { + // Send to Sentry, Crashlytics, etc. + reportToCrashService({ + message: err.message, + stack: err.stack, + timestamp: Date.now() + }) + } + } +} +Trace.setErrorHandler(errorHandler) + +// 4. Global error handlers +Application.on(Application.uncaughtErrorEvent, (args) => { + Trace.error(args.error) +}) + +Application.on(Application.discardedErrorEvent, (args) => { + Trace.error(args.error) +}) + +// 5. Start the app +Application.run({ moduleName: 'app-root' }) +``` + +### Trace API Quick Reference + +```typescript +// Categories +Trace.setCategories(categories: string) // Set allowed categories +Trace.addCategories(categories: string) // Add to existing categories +Trace.isCategorySet(category: string) // Check if category is set + +// Writing +Trace.write(message, category, type?) // Write a trace message +Trace.error(error: Error | string) // Pass error to handler + +// Writers +Trace.addWriter(writer: TraceWriter) // Add custom writer +Trace.removeWriter(writer: TraceWriter) // Remove a writer +Trace.clearWriters() // Remove all writers + +// Error handling +Trace.setErrorHandler(handler) // Set custom error handler +Trace.getErrorHandler() // Get current error handler + +// Enable/Disable +Trace.enable() // Enable tracing +Trace.disable() // Disable tracing +Trace.isEnabled() // Check if enabled +``` + +## Performance Tips + +1. **Minimize layout nesting** - Deep hierarchies hurt performance +2. **Use GridLayout** - Most flexible and performant for complex layouts +3. **Avoid method bindings** - Use property bindings instead +4. **Use template selectors** - For conditional ListView rows +5. **Prefer `hidden`/`visibility`** - Over `v-if`/`ngIf` during scroll +6. **Clean up resources** - Timers, listeners, observers +7. **Use Workers** - For heavy computation off main thread +8. **Optimize images** - Provide properly sized images for each density + +## Android Drawable Densities + +Place images in appropriate folders: +- `App_Resources/Android/src/main/res/drawable-mdpi/` - 1x +- `App_Resources/Android/src/main/res/drawable-hdpi/` - 1.5x +- `App_Resources/Android/src/main/res/drawable-xhdpi/` - 2x +- `App_Resources/Android/src/main/res/drawable-xxhdpi/` - 3x +- `App_Resources/Android/src/main/res/drawable-xxxhdpi/` - 4x + +## iOS Asset Catalog + +Place images in `App_Resources/iOS/Assets.xcassets/` with proper `@2x` and `@3x` suffixes. + +## Creating Custom View Elements + +When built-in elements don't meet your needs, create custom native elements. + +### Anatomy of a Custom View + +Every custom NativeScript view must have: +- (**required**) A class extending any NativeScript View +- (**required**) `createNativeView`: Construct and return a platform-native view +- (_optional_) `initNativeView`: Perform initialization after creation +- (_optional_) `disposeNativeView`: Cleanup resources when removed + +### Project Structure for Custom Views + +``` +./my-custom-view/ + ├── common.ts # Shared logic + ├── index.android.ts # Android implementation + ├── index.ios.ts # iOS implementation + └── index.d.ts # Type definitions +``` + +### Basic Custom View Example + +```typescript +import { View } from '@nativescript/core' + +export class CustomView extends View { + createNativeView() { + // iOS: return UIView instance + // Android: return android.view.View instance + } + + initNativeView() { + // initialization code + } + + disposeNativeView() { + // cleanup code + } +} +``` + +### Extending Existing Views + +You can extend any existing NativeScript view: + +```typescript +import { GridLayout, Label, Color, Property, booleanConverter, CoreTypes } from '@nativescript/core' + +export class Checkbox extends GridLayout { + checked = false + defaultColor = new Color('#dddddd') + selectionColor = new Color('#4CAF50') + private _iconLabel: Label + + constructor() { + super() + this.horizontalAlignment = 'center' + this.verticalAlignment = 'middle' + + this._iconLabel = new Label() + this._iconLabel.text = String.fromCharCode(0xf764) // circle icon + this._iconLabel.className = 'mat' // Material Design Icons font + this._iconLabel.color = this.defaultColor + this.addChild(this._iconLabel) + } + + toggle() { + this.checked = !this.checked + this._iconLabel.text = this.checked + ? String.fromCharCode(0xf5e0) // checkmark + : String.fromCharCode(0xf764) // circle + this._iconLabel.color = this.checked ? this.selectionColor : this.defaultColor + } +} +``` + +### Defining Customizable Properties + +```typescript +import { Property, booleanConverter, Color } from '@nativescript/core' + +const checkedProperty = new Property({ + name: 'checked', + defaultValue: false, + valueConverter: booleanConverter, +}) + +const sizeProperty = new Property({ + name: 'size', + defaultValue: 24, + affectsLayout: true, +}) + +const selectionColorProperty = new Property({ + name: 'selectionColor', + equalityComparer: Color.equals, + valueConverter: (v) => new Color(v), +}) + +// Implement setNative handlers +export class Checkbox extends GridLayout { + [checkedProperty.setNative](value: boolean) { + this.checked = value + this._updateVisual() + } + + [sizeProperty.setNative](value: number) { + this._iconLabel.fontSize = value + } + + [selectionColorProperty.setNative](value: Color) { + this.selectionColor = value + } +} + +// Register properties +checkedProperty.register(Checkbox) +sizeProperty.register(Checkbox) +selectionColorProperty.register(Checkbox) +``` + +### Registering Custom Elements by Framework + +**TypeScript (XML)** +```xml + + + + + +``` + +**Angular** +```typescript +import { registerElement } from '@nativescript/angular' +import { Checkbox } from './checkbox' +registerElement('Checkbox', () => Checkbox) +``` + +**Vue** +```typescript +import { registerElement } from 'nativescript-vue' +import { Checkbox } from './checkbox' +registerElement('Checkbox', () => Checkbox) +``` + +**Svelte** +```typescript +import { registerNativeViewElement } from '@nativescript-community/svelte-native/dom' +import { Checkbox } from './checkbox' +registerNativeViewElement('checkbox', () => Checkbox) +``` + +**React** +```typescript +import { registerElement } from 'react-nativescript' +import { Checkbox } from './checkbox' +registerElement('checkbox', () => Checkbox) +``` + +**Solid** +```typescript +import { registerElement } from 'dominative' +import { Checkbox } from './checkbox' +registerElement('checkbox', Checkbox) +``` + +### Customizing Existing View Elements + +Extend existing elements to customize behavior: + +```typescript +// index.ios.ts - Custom ListPicker with larger font +import { ListPicker } from '@nativescript/core' + +export class CustomListPicker extends ListPicker { + private _delegate: ListPickerDelegateImpl + + initNativeView() { + this._delegate = ListPickerDelegateImpl.initWithOwner(new WeakRef(this)) + this.nativeViewProtected.delegate = this._delegate + } +} + +@NativeClass() +class ListPickerDelegateImpl extends NSObject implements UIPickerViewDelegate { + static ObjCProtocols = [UIPickerViewDelegate] + private _owner: WeakRef + + static initWithOwner(owner: WeakRef): ListPickerDelegateImpl { + const delegate = ListPickerDelegateImpl.new() as ListPickerDelegateImpl + delegate._owner = owner + return delegate + } + + pickerViewViewForRowForComponentReusingView(pickerView: UIPickerView, row: number): UIView { + const owner = this._owner?.deref() + const label = UILabel.new() + label.font = UIFont.systemFontOfSize(26) // Custom font size + label.text = owner?.items[row] + label.textAlignment = NSTextAlignment.Center + return label + } +} +``` + +### createNativeView Platform Examples + +```typescript +// iOS +createNativeView() { + const config = WKWebViewConfiguration.new() + return new WKWebView({ frame: CGRectZero, configuration: config }) +} + +// Android +createNativeView() { + return new android.webkit.WebView(this._context) +} +``` + +## Resources + +- Documentation: https://docs.nativescript.org +- API Reference: https://docs.nativescript.org/api/ +- Plugins: https://docs.nativescript.org/plugins/ +- GitHub: https://github.com/NativeScript/NativeScript +- NativeScript Preview with Stackblitz: https://preview.nativescript.org/ +- JavaScript starter: https://nativescript.new/javascript +- TypeScript starter: https://nativescript.new/typescript +- Angular starter: https://nativescript.new/angular +- React starter: https://nativescript.new/react +- Solid starter: https://nativescript.new/solid +- Svelte starter: https://nativescript.new/svelte +- Vue starter: https://nativescript.new/vue +- Vue 3 starter: https://nativescript.new/vue3 diff --git a/content/sidebar.ts b/content/sidebar.ts index b46b1d64..770ddc4f 100644 --- a/content/sidebar.ts +++ b/content/sidebar.ts @@ -240,6 +240,15 @@ export default [ }, ] }, + { + text: 'Agentic Coding', + items: [ + { + text: 'Leverage AI assistants', + link: '/guide/agentic-coding', + } + ] + }, { text: 'Advanced Concepts', items: [