🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
242 lines
8.0 KiB
Plaintext
Executable File
242 lines
8.0 KiB
Plaintext
Executable File
NPM(3) RSX Framework Manual NPM(3)
|
|
|
|
NAME
|
|
npm - Including npm packages in RSX bundles
|
|
|
|
SYNOPSIS
|
|
// Asset Bundle with npm imports
|
|
class My_Bundle extends Rsx_Asset_Bundle_Abstract
|
|
{
|
|
public static function define(): array
|
|
{
|
|
return [
|
|
'npm' => [
|
|
'moment' => "import moment from 'moment'",
|
|
'axios' => "import axios from 'axios'",
|
|
],
|
|
];
|
|
}
|
|
}
|
|
|
|
// Usage in JavaScript
|
|
const now = moment().format('YYYY-MM-DD');
|
|
const response = await axios.get('/api/data');
|
|
|
|
DESCRIPTION
|
|
RSX bundles can include npm packages through Asset Bundles. The bundle
|
|
system uses esbuild to compile npm imports into the vendor bundle,
|
|
exposing them as global variables accessible throughout your application.
|
|
|
|
Unlike traditional webpack/vite setups where you write import statements
|
|
in your JavaScript files, RSX centralizes npm dependencies in Asset
|
|
Bundle definitions. This provides:
|
|
|
|
- Explicit dependency declaration in PHP
|
|
- Automatic vendor/app bundle splitting
|
|
- Tree-shaking of unused exports
|
|
- No import statements needed in application code
|
|
|
|
PACKAGE INSTALLATION
|
|
All npm packages must be installed in the system directory:
|
|
|
|
cd /var/www/html/system
|
|
npm install <package-name>
|
|
|
|
The framework's esbuild runs from system/, so packages must exist in
|
|
system/node_modules/. The project root package.json is for reference
|
|
only - actual dependencies live in system/.
|
|
|
|
ASSET BUNDLE SYNTAX
|
|
Create an Asset Bundle extending Rsx_Asset_Bundle_Abstract with an
|
|
'npm' array in the define() method:
|
|
|
|
class My_Library_Bundle extends Rsx_Asset_Bundle_Abstract
|
|
{
|
|
public static function define(): array
|
|
{
|
|
return [
|
|
'npm' => [
|
|
'global_name' => "import statement",
|
|
],
|
|
];
|
|
}
|
|
}
|
|
|
|
Each entry maps a global variable name to an ES module import statement.
|
|
The global becomes available to all JavaScript in bundles that include
|
|
this Asset Bundle.
|
|
|
|
IMPORT FORMATS
|
|
DEFAULT EXPORT
|
|
Package exports a single default value:
|
|
|
|
'moment' => "import moment from 'moment'",
|
|
'axios' => "import axios from 'axios'",
|
|
'lodash' => "import _ from 'lodash'",
|
|
|
|
Usage: moment(), axios.get(), _.map()
|
|
|
|
NAMED EXPORT
|
|
Package exports multiple named values. Each named export needs its
|
|
own entry:
|
|
|
|
// CORRECT - separate entries for each named export
|
|
'createApp' => "import { createApp } from 'vue'",
|
|
'ref' => "import { ref } from 'vue'",
|
|
'computed' => "import { computed } from 'vue'",
|
|
|
|
Usage: createApp(), ref(), computed()
|
|
|
|
IMPORTANT: You cannot combine multiple named exports into one global.
|
|
This does NOT work:
|
|
|
|
// WRONG - creates single value, not object with both
|
|
'vue' => "import { createApp, ref } from 'vue'",
|
|
|
|
The global 'vue' would only contain createApp, not both functions.
|
|
|
|
NAMESPACE IMPORT
|
|
Import all exports as a namespace object:
|
|
|
|
'Shiki' => "import * as Shiki from 'shiki'",
|
|
|
|
Usage: Shiki.createHighlighter(), Shiki.bundledLanguages
|
|
|
|
SUB-PATH IMPORTS
|
|
Many packages offer sub-path imports for tree-shaking:
|
|
|
|
// Full package - includes everything
|
|
'shiki' => "import { createHighlighter } from 'shiki'",
|
|
|
|
// Sub-path - only what you need
|
|
'createHighlighter' => "import { createHighlighterCore } from '@shikijs/core'",
|
|
'darkPlus' => "import darkPlus from '@shikijs/themes/dark-plus'",
|
|
|
|
Sub-path imports significantly reduce bundle size.
|
|
|
|
BUNDLE PLACEMENT
|
|
Asset Bundles are auto-discovered when Module Bundles scan directories.
|
|
Place your npm Asset Bundle alongside the components that use it:
|
|
|
|
rsx/app/docs/components/
|
|
shiki_bundle.php # Asset Bundle with npm imports
|
|
Docs_Code_Block.js # Component using shiki globals
|
|
Docs_Code_Block.jqhtml
|
|
|
|
The Module Bundle scanning rsx/app/docs/ will automatically include
|
|
the Shiki_Bundle and its npm dependencies.
|
|
|
|
VENDOR BUNDLE COMPILATION
|
|
npm packages compile into the vendor bundle, separate from app code.
|
|
This provides better caching since vendor code changes less frequently.
|
|
|
|
REBUILD TRIGGERS
|
|
The vendor bundle rebuilds when:
|
|
- npm entries in Asset Bundles change
|
|
- First HTTP request after cache clear
|
|
- Running rsx:clean followed by page request
|
|
|
|
IMPORTANT: Running rsx:bundle:compile alone may not rebuild the
|
|
vendor bundle if the cache key hasn't changed. To force a complete
|
|
rebuild:
|
|
|
|
php artisan rsx:bundle:compile --clean
|
|
|
|
Or trigger via HTTP request:
|
|
|
|
curl http://localhost/your-page
|
|
php artisan rsx:debug /your-page
|
|
|
|
TROUBLESHOOTING
|
|
NPM MODULE NOT FOUND ERROR
|
|
Error: RSX Framework Error: NPM module "xyz" not found.
|
|
Expected window._rsx_npm.xyz to be defined by the vendor bundle.
|
|
|
|
Causes:
|
|
1. Package not installed in system/node_modules/
|
|
2. Vendor bundle not rebuilt after adding npm entry
|
|
3. Import statement syntax error
|
|
|
|
Solutions:
|
|
1. cd system && npm install <package>
|
|
2. php artisan rsx:bundle:compile --clean
|
|
3. Verify import syntax matches package's actual exports
|
|
|
|
VERIFYING PACKAGE EXPORTS
|
|
Check what a package actually exports:
|
|
|
|
# Default export
|
|
grep -E "^export default" node_modules/pkg/dist/index.mjs
|
|
|
|
# Named exports
|
|
grep -E "^export \{|^export function|^export const" \
|
|
node_modules/pkg/dist/index.mjs
|
|
|
|
BUNDLE SIZE OPTIMIZATION
|
|
Use sub-path imports when available:
|
|
|
|
// Before: 9.7 MB (all languages, themes)
|
|
'shiki' => "import { createHighlighter } from 'shiki'",
|
|
|
|
// After: 2.4 MB (only what's needed)
|
|
'createHighlighter' => "import { createHighlighterCore } from '@shikijs/core'",
|
|
'langJs' => "import js from '@shikijs/langs/javascript'",
|
|
'themeDark' => "import dark from '@shikijs/themes/dark-plus'",
|
|
|
|
EXAMPLES
|
|
CHART.JS
|
|
class Chart_Bundle extends Rsx_Asset_Bundle_Abstract
|
|
{
|
|
public static function define(): array
|
|
{
|
|
return [
|
|
'npm' => [
|
|
'Chart' => "import { Chart } from 'chart.js/auto'",
|
|
],
|
|
];
|
|
}
|
|
}
|
|
|
|
// Usage
|
|
new Chart(ctx, { type: 'bar', data: {...} });
|
|
|
|
DATE-FNS (Tree-Shaking Friendly)
|
|
class DateFns_Bundle extends Rsx_Asset_Bundle_Abstract
|
|
{
|
|
public static function define(): array
|
|
{
|
|
return [
|
|
'npm' => [
|
|
'format' => "import { format } from 'date-fns'",
|
|
'parseISO' => "import { parseISO } from 'date-fns'",
|
|
'addDays' => "import { addDays } from 'date-fns'",
|
|
],
|
|
];
|
|
}
|
|
}
|
|
|
|
// Usage
|
|
format(parseISO('2024-01-15'), 'MMM d, yyyy');
|
|
|
|
VUE 3
|
|
class Vue_Bundle extends Rsx_Asset_Bundle_Abstract
|
|
{
|
|
public static function define(): array
|
|
{
|
|
return [
|
|
'npm' => [
|
|
'createApp' => "import { createApp } from 'vue'",
|
|
'ref' => "import { ref } from 'vue'",
|
|
'reactive' => "import { reactive } from 'vue'",
|
|
'computed' => "import { computed } from 'vue'",
|
|
'watch' => "import { watch } from 'vue'",
|
|
],
|
|
];
|
|
}
|
|
}
|
|
|
|
SEE ALSO
|
|
bundle_api(3), jqhtml(3)
|
|
|
|
RSX Framework 2025-12-09 NPM(3)
|