{"id":19220101,"url":"https://github.com/nativescript-community/xml-ui-loader","last_synced_at":"2025-04-10T19:52:34.323Z","repository":{"id":58302068,"uuid":"528182814","full_name":"nativescript-community/xml-ui-loader","owner":"nativescript-community","description":null,"archived":false,"fork":false,"pushed_at":"2023-05-19T18:01:38.000Z","size":459,"stargazers_count":4,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-24T17:51:30.217Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/nativescript-community.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2022-08-23T22:28:50.000Z","updated_at":"2023-12-24T10:50:14.000Z","dependencies_parsed_at":"2024-11-09T14:37:30.377Z","dependency_job_id":"88f6a830-845b-4905-95d2-bd984fb13078","html_url":"https://github.com/nativescript-community/xml-ui-loader","commit_stats":{"total_commits":129,"total_committers":2,"mean_commits":64.5,"dds":0.007751937984496138,"last_synced_commit":"d29d5a93516c18c1cbecf8b1f96bdd5a304eb521"},"previous_names":[],"tags_count":13,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nativescript-community%2Fxml-ui-loader","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nativescript-community%2Fxml-ui-loader/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nativescript-community%2Fxml-ui-loader/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/nativescript-community%2Fxml-ui-loader/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/nativescript-community","download_url":"https://codeload.github.com/nativescript-community/xml-ui-loader/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248284094,"owners_count":21077992,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-09T14:34:00.642Z","updated_at":"2025-04-10T19:52:34.288Z","avatar_url":"https://github.com/nativescript-community.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# @nativescript-community/xml-ui-loader\n\n[![npm](https://img.shields.io/npm/v/@nativescript-community/xml-ui-loader.svg)](https://www.npmjs.com/package/@nativescript-community/xml-ui-loader)\n[![npm](https://img.shields.io/npm/dt/@nativescript-community/xml-ui-loader.svg?label=npm%20downloads)](https://www.npmjs.com/package/@nativescript-community/xml-ui-loader)\n[![GitHub forks](https://img.shields.io/github/forks/nativescript-community/xml-ui-loader.svg)](https://github.com/nativescript-community/xml-ui-loader/network)\n[![GitHub stars](https://img.shields.io/github/stars/nativescript-community/xml-ui-loader.svg)](https://github.com/nativescript-community/xml-ui-loader/stargazers)\n\nThis is a [webpack](https://webpack.js.org) loader for [NativeScript](https://nativescript.org).  \n\nBy default, NativeScript Core uses a builder to compile XML components at runtime and that happens every time there is a need to render views.  \nThis new approach is meant to work as an ahead-of-time (AOT) compiler that turns XML content into JavaScript during the build phase.  \nIt's meant to improve performance and allow developers to use XML files as modules.\n\n## Table of Contents\n\n- [Install](#install)\n- [Setup](#setup)\n  - [TypeScript](#typescript)\n  - [Webpack](#webpack)\n- [Usage](#usage)\n  - [Import as a module](#import-as-a-module)\n  - [Import as plain XML](#import-as-plain-xml)\n- [Features](#features)\n  - [Data binding](#data-binding)\n  - [Custom components](#custom-components)\n  - [Script and Style](#script-and-style)\n  - [Slots](#slots)\n    - [Declaration](#declaration)\n    - [Targeting slots](#targeting-slots)\n    - [Slot fallback](#slot-fallback)\n    - [Using slots in JS/TS components](#using-slots-in-jsts-components)\n- [License](#license)\n\n\n## Install\n\n```\nnpm install @nativescript-community/xml-ui-loader --save-dev\n```\n\n\n## Setup\n\n### TypeScript\n\nAdd XML module declaration to your types:\n\n`references.d.ts`\n```ts\n/// \u003creference path=\"./node_modules/@nativescript/types/index.d.ts\" /\u003e\n\ndeclare module '*.xml';\n```\n\n### Webpack\n\nThis loader requires a new configuration:\n\n`webpack.config.js`\n```javascript\nconst webpack = require('@nativescript/webpack');\nconst { getEntryDirPath, getPlatformName } = require('@nativescript/webpack/dist/helpers/platform');\nconst { chainLoaderConfiguration } = require(\"@nativescript-community/xml-ui-loader/dist/helpers\");\n\nmodule.exports = (env) =\u003e {\n  webpack.init(env);\n\n  // Learn how to customize:\n  // https://docs.nativescript.org/webpack\n\n  webpack.chainWebpack((config) =\u003e {\n    chainLoaderConfiguration(config, {\n      appPath: getEntryDirPath(),\n      platform: getPlatformName()\n    });\n  });\n\n  return webpack.resolveConfig();\n};\n```\n\nThere are also few preprocessing options that are useful for applying output customizations.\n```javascript\nchainLoaderConfiguration(config, {\n  appPath: getEntryDirPath(),\n  platform: getPlatformName(),\n  useDataBinding: false, // Set this to false if you don't want to use data binding system\n  preprocess: {\n    // Format attribute value\n    attributeValueFormatter: (value, attributeName, tagName, attributes) =\u003e value.toUpperCase(),\n    // Manage AST result\n    transformAst: (ast, generateFunc) =\u003e generateFunc(ast).code,\n  }\n});\n\n```\n\n\n## Usage\n\n### Import as a module\n\nOne can easily import an XML component just like any regular JS module using either a default or a named import.  \nExample:\n```javascript\n// Default import\nimport MyActionBar123 from \"./components/my-action-bar.xml\";\n// Named import\nimport { MyActionBar } from \"./components/my-action-bar.xml\";\n```\n\n### Import as plain XML\n\nTo import the raw content of an XML file, append an XML declaration to it.  \nExample:\n```xml\n\u003c?xml version=\"1.0\" encoding=\"UTF-8\"?\u003e\n\u003clist\u003e\n  ...\n\u003c/list\u003e\n```\nThis will make sure import will resolve to plain XML string content.\n\n\n## Features\n\n### Data binding\n\nData bindings are supported using MVVM pattern by setting view's `bindingContext` property on JS side.\n```xml\n\u003c!-- Property binding --\u003e\n\u003cPage\u003e\n  \u003cGridLayout\u003e\n    \u003cLabel text=\"{{ myTextProp }}\"/\u003e\n  \u003c/GridLayout\u003e\n\u003c/Page\u003e\n\n\u003c!-- Event binding --\u003e\n\u003cPage\u003e\n  \u003cGridLayout\u003e\n    \u003cLabel text=\"Hello world!\" on:tap=\"{{ onHelloWorldTap }}\"/\u003e\n  \u003c/GridLayout\u003e\n\u003c/Page\u003e\n\n\u003c!-- Property converters --\u003e\n\u003cPage\u003e\n  \u003cGridLayout\u003e\n    \u003cLabel text=\"{{ myTextProp | toUpperCaseConverter }}\"/\u003e\n  \u003c/GridLayout\u003e\n\u003c/Page\u003e\n```\n\nNote: Two-way binding is enabled by default. However, events, sub-properties and expressions that make use of `$value`, `$parent`, or `$parents` callers do not support it.\n\n### Custom components\n\nRegarding custom components, they can be used in markup by declaring namespaces.  \nA namespace works just like a named import.\n\nA correct approach, supposing caller directory path is `app/views/home` and components directory path is `app/components`\n```xml\n\u003cPage xmlns:myxml=\"../../components/my-xml-component.xml\" xmlns:myjs=\"../../components/my-js-component\"\u003e\n  \u003cmyjs:MyJsComponent/\u003e\n  \u003c!-- OR --\u003e\n  \u003cmyjs:default/\u003e\u003c!-- in case module has a default export --\u003e\n\u003c/Page\u003e\n```\n\n### Script and Style\n\nIn general, one is able to create script and style files for an XML component provided that they use the same filename.  \nThe first contains useful entities like events used by XML and the latter applies all CSS to it.  \n\nThere is also a forgotten method to bind scripts or styles to XML.  \nIt's `codeFile` and `cssFile` properties. These properties are assigned to top element inside an XML file and are especially useful when one wishes to bind a single script or style file with multiple components.  \n\n```xml\n\u003c!-- Script --\u003e\n\u003cPage codeFile=\"~/views/common/myscript\"\u003e\n\u003c/Page\u003e\n\n\u003c!-- CSS --\u003e\n\u003cPage cssFile=\"~/views/common/mystyle\"\u003e\n\u003c/Page\u003e\n```\n\n### Slots\n\nCustom components can make one's code reusable but there is always the need to have total control over view nesting as they can be quite complex at times.  \nHere comes the concept of `slots`. Inspired from the web component [slot](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot) element, slots ensure that custom components can be extremely flexible on reusing at different cases that demand different view content.  \nFor more information, see: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/slot  \n\n#### Declaration\n\nA plain slot that behaves as default\n```xml\n\u003c!-- my-custom-view.xml --\u003e\n\u003cStackLayout\u003e\n  \u003cslot/\u003e\n\u003c/StackLayout\u003e\n```\n\nA named slot\n```xml\n\u003c!-- my-custom-view.xml --\u003e\n\u003cStackLayout\u003e\n  \u003cslot name=\"page-content\"/\u003e\n\u003c/StackLayout\u003e\n```\n\n#### Targeting slots\n\nIn order to target slots and keep NativeScript existing nesting behaviour intact at the same time, one must declare slot views inside a `slotContent` element.\n```xml\n\u003c!-- my-page.xml --\u003e\n\u003cPage xmlns:mcv=\"../my-custom-view.xml\"\u003e\n  \u003cmcv:MyCustomView\u003e\n    \u003cslotContent\u003e\n      \u003cLabel text=\"Hello\"/\u003e\n    \u003c/slotContent\u003e\n  \u003c/mcv:MyCustomView\u003e\n\u003c/Page\u003e\n```\n\nNamed slots can be targeted using the `slot` attribute.\n```xml\n\u003c!-- my-page.xml --\u003e\n\u003cPage xmlns:mcv=\"../my-custom-view.xml\"\u003e\n  \u003cmcv:MyCustomView\u003e\n    \u003cslotContent\u003e\n      \u003cLabel slot=\"page-content\" text=\"Hello\"/\u003e\n    \u003c/slotContent\u003e\n  \u003c/mcv:MyCustomView\u003e\n\u003c/Page\u003e\n```\n\nThere is also the option of targeting a slot using multiple views.\n```xml\n\u003c!-- my-page.xml --\u003e\n\u003cPage xmlns:mcv=\"../my-custom-view.xml\"\u003e\n  \u003cmcv:MyCustomView\u003e\n    \u003cslotContent\u003e\n      \u003cLabel text=\"Hello\"/\u003e\n      \u003cLabel text=\"there\"/\u003e\n    \u003c/slotContent\u003e\n  \u003c/mcv:MyCustomView\u003e\n\u003c/Page\u003e\n```\nor\n```xml\n\u003c!-- my-page.xml --\u003e\n\u003cPage xmlns:mcv=\"../my-custom-view.xml\"\u003e\n  \u003cmcv:MyCustomView\u003e\n    \u003cslotContent\u003e\n      \u003cLabel slot=\"page-content\" text=\"Hello\"/\u003e\n      \u003cLabel slot=\"page-content\" text=\"there\"/\u003e\n    \u003c/slotContent\u003e\n  \u003c/mcv:MyCustomView\u003e\n\u003c/Page\u003e\n```\n\nApart from views, slots can also target other slots.\n```xml\n\u003c!-- my-page.xml --\u003e\n\u003cPage xmlns:mcv=\"../my-custom-view.xml\"\u003e\n  \u003cmcv:MyCustomView\u003e\n    \u003cslotContent\u003e\n      \u003cslot name=\"the-other-slot\" slot=\"page-content\"/\u003e\n    \u003c/slotContent\u003e\n  \u003c/mcv:MyCustomView\u003e\n\u003c/Page\u003e\n```\n\n#### Slot fallback\n\nFallback refers to the content (one or more views) that is rendered when no view(s) target the slot.\n```xml\n\u003c!-- my-custom-view.xml --\u003e\n\u003cStackLayout\u003e\n  \u003cslot\u003e\n    \u003cLabel text=\"Not found!\"/\u003e\n    \u003cLabel text=\"Really?\"/\u003e\n  \u003c/slot\u003e\n\u003c/StackLayout\u003e\n```\n\n#### Using slots in JS/TS components\n\nThere is also the possibility of making use of slot functionality into script components.\n```js\nimport { StackLayout } from '@nativescript/core';\n\nclass MyCustomView extends StackLayout {\n  // Constructor has sole access to slot views\n  constructor() {\n    super();\n\n    // $slotViews is an array of views\n    if (this.$slotViews['default']) {\n      for (const view of this.$slotViews['default']) {\n        this.addChild(view);\n      }\n    }\n  }\n}\n\nexport {\n  MyCustomView\n}\n```\n\n```xml\n\u003c!-- my-page.xml --\u003e\n\u003cPage xmlns:mcv=\"../my-custom-view\"\u003e\n  \u003cmcv:MyCustomView\u003e\n    \u003cslotContent\u003e\n      \u003cLabel text=\"Hello\"/\u003e\n    \u003c/slotContent\u003e\n  \u003c/mcv:MyCustomView\u003e\n\u003c/Page\u003e\n```\n\n\n## License\n\nApache-2.0","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnativescript-community%2Fxml-ui-loader","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fnativescript-community%2Fxml-ui-loader","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fnativescript-community%2Fxml-ui-loader/lists"}