Version: 3.0
Date: February 7, 2026
Status: Universal Runtime
TizenPortal uses Rollup with Babel to bundle ES6+ source code into an ES5-compatible IIFE that runs on Samsung Tizen TVs (Chrome 47-69).
The build system produces one universal output:
| Output | Input | Size | Purpose |
|---|---|---|---|
dist/tizenportal.js |
core/index.js |
~320KB | Universal runtime for portal and target sites |
TizenPortal operates as a TizenBrew MOD module with a unified runtime:
tizenportal.js into ALL pagesThe same script runs everywhere, detecting context automatically.
{
"devDependencies": {
"rollup": "^4.0.0",
"@rollup/plugin-babel": "^6.0.0",
"@rollup/plugin-node-resolve": "^15.0.0",
"@rollup/plugin-commonjs": "^25.0.0",
"@rollup/plugin-replace": "^6.0.3",
"@rollup/plugin-terser": "^0.4.0",
"@babel/core": "^7.23.0",
"@babel/preset-env": "^7.23.0",
"rollup-plugin-string": "^3.0.0"
},
"dependencies": {
"core-js": "^3.47.0",
"whatwg-fetch": "^3.6.20",
"spatial-navigation-polyfill": "^1.3.1"
}
}
npm install
The configuration builds a single universal runtime:
// rollup.config.js
import { string } from 'rollup-plugin-string';
import terser from '@rollup/plugin-terser';
import babel from '@rollup/plugin-babel';
import { nodeResolve } from '@rollup/plugin-node-resolve';
import commonjs from '@rollup/plugin-commonjs';
import replace from '@rollup/plugin-replace';
import { readFileSync } from 'fs';
// Read version from package.json - single source of truth
const pkg = JSON.parse(readFileSync('./package.json', 'utf-8'));
const VERSION = pkg.version;
// Shared plugins
const plugins = [
// Replace __VERSION__ placeholder with actual version
replace({
preventAssignment: true,
values: { '__VERSION__': VERSION },
}),
// Import CSS files as strings
string({ include: '**/*.css' }),
// Resolve node_modules imports
nodeResolve({ browser: true, preferBuiltins: false }),
// Convert CommonJS modules to ES modules
commonjs({ include: [/node_modules/], transformMixedEsModules: true }),
// Transpile to ES5 for Chrome 47+ compatibility
babel({
babelHelpers: 'bundled',
presets: [['@babel/preset-env', { targets: { chrome: '47' }, modules: false }]],
exclude: 'node_modules/**',
}),
// Minify output
terser({ ecma: 5, mangle: true, compress: { drop_console: false } }),
];
export default [
// Single build: Universal runtime
{
input: 'core/index.js',
output: {
file: 'dist/tizenportal.js',
format: 'iife',
name: 'TizenPortal',
sourcemap: false,
},
plugins,
},
];
| Plugin | Purpose |
|---|---|
@rollup/plugin-replace |
Inject version from package.json at build time |
rollup-plugin-string |
Import CSS files as strings |
@rollup/plugin-node-resolve |
Resolve imports from node_modules |
@rollup/plugin-commonjs |
Convert CommonJS to ES modules |
@rollup/plugin-babel |
Transpile ES6+ syntax to ES5 |
@rollup/plugin-terser |
Minify output |
Version is centralized in package.json and injected at build time.
{ "version": "XXYY" } // e.g., "1018" for v1.0.18
const pkg = JSON.parse(readFileSync('./package.json', 'utf-8'));
const VERSION = pkg.version;
__VERSION__ in source code:
replace({ values: { '__VERSION__': VERSION } })
const VERSION = '__VERSION__'; // Replaced with package.json version at build time
Defined in package.json:
{
"scripts": {
"build": "rollup -c",
"watch": "rollup -c --watch",
"clean": "node -e \"require('fs').rmSync('dist/tizenportal.js', {force: true})\""
}
}
| Command | Purpose |
|---|---|
npm run build |
Production build (minified) |
npm run watch |
Development with auto-rebuild |
npm run clean |
Remove built files |
dist/
├── index.html # Portal HTML (manually maintained)
└── tizenportal.js # Built runtime (~320KB minified)
// dist/tizenportal.js (IIFE format)
var TizenPortal = (function () {
'use strict';
// Polyfills (core-js, fetch, DOMRect)
// Spatial navigation polyfill
// Configuration system
// Input handling
// Focus management
// UI components
// Bundle registry
// Core initialization
return {
version: 'XXYY', // Injected from package.json at build time
config: {...},
input: {...},
focus: {...},
keys: {...},
log: function() {...},
// ... more exports
};
})();
| Metric | Target | Actual |
|---|---|---|
| Minified | < 400KB | ~320KB |
| Gzipped | < 100KB | ~80KB |
The build includes:
# 1. Start watch mode
npm run watch
# 2. Edit source files
# 3. Build auto-runs on save
# 4. Test on TV or emulator
core/, ui/, bundles/, etc.dist/ folder to testbundles/my-bundle/main.js, style.css, manifest.jsonbundles/registry.jsnpm run buildSince the runtime is injected by TizenBrew, local testing requires:
dist/index.html locally for portal UI# 1. Update version in package.json
"version": "0392"
# 2. Rebuild
npm run build
# 3. Commit and tag
git add .
git commit -m "Bump to 0392"
git tag 0392
git push origin master --tags
The dist/ folder is deployed to GitHub Pages:
https://axelnanol.github.io/tizenportal/dist/index.html
https://axelnanol.github.io/tizenportal/dist/tizenportal.js
TizenBrew caches by git tag. To update:
0392)Important: Without a new tag, TizenBrew serves cached old code!
# Clear node_modules and rebuild
rm -rf node_modules
npm install
npm run build
npm run buildgrep "version" dist/tizenportal.jsbundles/ folderbundles/registry.jsCSS files are imported as strings:
// In bundle main.js
import styles from './style.css';
export default {
style: styles, // String of CSS content
// ...
};
The rollup-plugin-string plugin handles this.
Babel transpiles modern JavaScript:
| ES6+ Feature | ES5 Output |
|---|---|
| Arrow functions | Regular functions |
| const/let | var |
| Classes | Constructor functions |
| Template literals | String concatenation |
| Spread operator | Array.concat / Object.assign |
| Async/await | Not supported (avoid using) |
Via core-js and whatwg-fetch:
PromiseObject.assignArray.from, Array.ofArray.prototype.find, findIndexString.prototype.includesfetch APIEnd of Build System Documentation