{"id":13508523,"url":"https://github.com/jridgewell/babel-plugin-transform-incremental-dom","last_synced_at":"2025-03-30T11:32:11.711Z","repository":{"id":34862804,"uuid":"38863124","full_name":"jridgewell/babel-plugin-transform-incremental-dom","owner":"jridgewell","description":"Turn JSX into IncrementalDOM","archived":true,"fork":false,"pushed_at":"2021-03-31T02:35:21.000Z","size":989,"stargazers_count":145,"open_issues_count":10,"forks_count":12,"subscribers_count":9,"default_branch":"master","last_synced_at":"2024-04-24T08:00:00.188Z","etag":null,"topics":["babel-plugin","incremental-dom","jsx"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/jridgewell.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-07-10T05:41:30.000Z","updated_at":"2024-04-15T20:41:17.000Z","dependencies_parsed_at":"2022-08-03T23:00:29.232Z","dependency_job_id":null,"html_url":"https://github.com/jridgewell/babel-plugin-transform-incremental-dom","commit_stats":null,"previous_names":["jridgewell/babel-plugin-incremental-dom"],"tags_count":26,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jridgewell%2Fbabel-plugin-transform-incremental-dom","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jridgewell%2Fbabel-plugin-transform-incremental-dom/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jridgewell%2Fbabel-plugin-transform-incremental-dom/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/jridgewell%2Fbabel-plugin-transform-incremental-dom/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/jridgewell","download_url":"https://codeload.github.com/jridgewell/babel-plugin-transform-incremental-dom/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246314011,"owners_count":20757450,"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":["babel-plugin","incremental-dom","jsx"],"created_at":"2024-08-01T02:00:54.343Z","updated_at":"2025-03-30T11:32:06.700Z","avatar_url":"https://github.com/jridgewell.png","language":"JavaScript","funding_links":[],"categories":["JavaScript","DOM 差分レンダリング"],"sub_categories":[],"readme":"# babel-plugin-transform-incremental-dom [![Build Status](https://travis-ci.org/jridgewell/babel-plugin-transform-incremental-dom.svg?branch=master)](https://travis-ci.org/jridgewell/babel-plugin-transform-incremental-dom)\n\nTurn JSX into [Incremental DOM](http://google.github.io/incremental-dom/).\n\n## Example\n\n**In**\n\n```javascript\nexport default function render(data) {\n    var header = data.conditional ? \u003cdiv /\u003e : null;\n    var collection = data.items.map((item) =\u003e {\n        return \u003cli key={item.id} class={item.className}\u003e{item.name}\u003c/li\u003e;\n    });\n\n    return \u003cdiv id=\"container\"\u003e\n        {header}\n        \u003cul\u003e{collection}\u003c/ul\u003e\n        \u003cp {...data.props}\u003eSome features\u003c/p\u003e\n    \u003c/div\u003e;\n}\n```\n\n**Out** (default, unoptimized options)\n\n```javascript\nconst _li$statics = [\"key\", \"\"];\nconst _li$wrapper = function (_item$id, _item$className, _item$name) {\n    _li$statics[1] = _item$id;\n    elementOpen(\"li\", _item$id, _li$statics, \"class\", _item$className);\n      _renderArbitrary(_item$name);\n    return elementClose(\"li\");\n};\n\nconst _header$wrapper = function () {\n    return elementVoid(\"div\");\n};\n\nconst _div$statics = [\"id\", \"container\"];\nfunction render(data) {\n    var header = data.conditional ? _jsxWrapper(_header$wrapper) : null;\n    var collection = data.items.map(item =\u003e {\n        return _jsxWrapper(_li$wrapper, [item.id, item.className, item.name]);\n    });\n\n    elementOpen(\"div\", \"ab4a1d60-7353-4d98-b1f5-2682f1bc2b3c\", _div$statics);\n\n      _renderArbitrary(header);\n\n      elementOpen(\"ul\");\n        _renderArbitrary(collection);\n      elementClose(\"ul\");\n\n      elementOpenStart(\"p\");\n      _spreadAttribute(data.props);\n      elementOpenEnd(\"p\");\n        text(\"Some features\");\n      elementClose(\"p\");\n\n    return elementClose(\"div\");\n}\n\n\n// Helpers\n// -------\n\nvar _jsxWrapper = function _jsxWrapper(func, args) {\n    return {\n        __jsxDOMWrapper: true,\n        func: func,\n        args: args\n    };\n};\n\nvar _flipAttr = function _flipAttr(value, name) {\n    attr(name, value);\n};\n\nvar _spreadAttribute = function _spreadAttribute(spread) {\n    _forOwn(spread, _flipAttr);\n};\n\nvar _hasOwn = Object.prototype.hasOwnProperty;\n\nvar _forOwn = function _forOwn(object, iterator) {\n    for (var prop in object) if (_hasOwn.call(object, prop)) iterator(object[prop], prop);\n};\n\nvar _renderArbitrary = function _renderArbitrary(child) {\n    var type = typeof child;\n\n    if (type === \"number\" || type === \"string\" || type === \"object\" \u0026\u0026 child instanceof String) {\n        text(child);\n    } else if (Array.isArray(child)) {\n        child.forEach(_renderArbitrary);\n    } else if (type === \"object\") {\n        if (child.__jsxDOMWrapper) {\n            var func = child.func,\n                args = child.args;\n\n            if (args) {\n                func.apply(this, args);\n            } else {\n                func();\n            }\n        } else if (String(child) === \"[object Object]\") {\n            _forOwn(child, _renderArbitrary);\n        }\n    }\n};\n\n```\n\n## Installation\n\n```sh\n$ npm install babel-plugin-transform-incremental-dom\n```\n\n## Usage\n\n### Via `.babelrc` (Recommended)\n\n**.babelrc**\n\n```json\n{\n  \"presets\": [\"es2015\"],\n  \"plugins\": [\"transform-incremental-dom\"]\n}\n```\n\nAny of the [configuration options](#options) may also be passed.\n\n### Via CLI\n\n```sh\n$ babel --plugins transform-incremental-dom script.js\n```\n\n### Via Node API\n\n```javascript\nrequire(\"babel-core\").transform(\"code\", {\n  \"presets\": [\"es2015\"],\n  \"plugins\": [\"transform-incremental-dom\"],\n});\n```\n\nAny of the [configuration options](#options) may also be passed.\n\n### Options\n\n#### Require Statics Key\n\nIncremental DOM [recommends](http://google.github.io/incremental-dom/#rendering-dom/statics-array)\nonly using static attribute arrays when a `key` is specified. For that\nreason this plugin will automatically generate a UUID key if there is\nnot one and there are static attributes.\n\nAlternatively, you may disable the automatic generation. In this case,\nstatic attributes will be deoptimized into the dynamic attributes list.\n\n```javascript\n// Disabled (default)\nvar _statics = [\"key\", \"key\", \"href\", \"http://key/specified\"];\nvar _statics2 = [\"href\", \"http://example.com\"];\nvar _statics3 = [\"href\", \"http://other.com\"];\n\nfunction render() {\n  elementVoid(\"a\", \"key\", _statics);\n  if (condition)\n    elementVoid(\"a\", \"8ad02822-f391-48fb-a277-8065f7f92a99\", _statics2);\n  } else {\n    elementVoid(\"a\", \"adbe4414-e6ad-41c0-aae2-1ca578653119\", _statics3);\n  }\n}\n```\n\n```javascript\n// Enabled\nvar _statics = [\"key\", \"key\", \"href\", \"http://key/specified\"];\n\nfunction render(condition) {\n  elementVoid(\"a\", \"key\", _statics);\n  if (condition)\n    elementVoid(\"a\", null, null, \"href\", \"http://example.com\");\n  } else {\n    elementVoid(\"a\", null, null, \"href\", \"http://other.com\");\n  }\n}\n```\n\nTo do this, simply add the `requireStaticsKey` option to the Incremental DOM\nplugin:\n\n```json\n{\n  \"plugins\": [[\n    \"transform-incremental-dom\", {\n      \"requireStaticsKey\": true\n    }\n  ]]\n}\n```\n\n#### UUID Prefix\n\nTogether with automatic UUID generation, you can specify a UUID \"prefix\"\nthat will allow for shorter automatic keys. You must ensure that this\nprefix will not conflict with any other value you use as a key.\n\nWhen using the UUID prefix, a simple counter is used instead of creating\na true UUID.\n\n```javascript\n// Disabled (default)\nvar _statics = [\"href\", \"http://example.com\"];\n\nfunction render() {\n  elementVoid(\"a\", \"8ad02822-f391-48fb-a277-8065f7f92a99\", _statics);\n}\n```\n\n```javascript\n// Enabled (\"uuid-\")\nvar _statics = [\"href\", \"http://example.com\"];\n\nfunction render() {\n  elementVoid(\"a\", \"uuid-1\", _statics);\n}\n```\n\nTo do this, simply add the `uuidPrefix` option to the Incremental DOM\nplugin:\n\n```json\n{\n  \"plugins\": [[\n    \"transform-incremental-dom\", {\n      \"uuidPrefix\": \"uuid-\"\n    }\n  ]]\n}\n```\n\n#### Namspaced Attributes\n\nIncremental DOM supports a few Attribute Namespaces, but those are\nforeign to JSX. You can enabled them with the `namespaceAttributes`\noption. Note that this does not enable Namespaced Elements.\n\n```javascript\n// Enabled\nfunction render() {\n    return elementVoid(\"a\", null, [\"xml:static\", true], \"xlink:href\", \"https\");\n}\n```\n\nTo do this, simply add the `namespaceAttributes` option to the\nIncremental DOM plugin:\n\n```json\n{\n  \"plugins\": [[\n    \"transform-incremental-dom\", {\n      \"namespaceAttributes\": true\n    }\n  ]]\n}\n```\n\n#### Inline JSX Expressions\n\nYou may enable the experimental `inlineExpressions` option to attempt to\ninline any variables declared outside the root JSX element. This can\nsave you from allocating needless closure wrappers around elements that\nare only referenced inside the root element.\n\n\n```javascript\n// Disabled (default)\nfunction render() {\n  var header = _jsxWrapper(function () {\n    return elementVoid(\"header\");\n  });\n  elementOpen(\"body\");\n\n  _renderArbitrary(header);\n\n  return elementClose(\"body\");\n}\n```\n\n```javascript\n// Enabled\nfunction render() {\n  elementOpen(\"body\");\n  elementVoid(\"header\");\n  return elementClose(\"body\");\n}\n```\n\nTo do this, simply add the `inlineExpressions` option to the Incremental DOM\nplugin:\n\n```json\n{\n  \"plugins\": [[\n    \"transform-incremental-dom\", {\n      \"inlineExpressions\": true\n    }\n  ]]\n}\n```\n\n#### Fast Root\n\nYou may enable the experimental `fastRoot` option so that JSX tags\ninside the root element are never wrapped inside a closure. For code\nwith array maps, this should significantly decrease memory usage and\nincrease speed.\n\n\n```javascript\n// Disabled (default)\nfunction render() {\n  elementOpen(\"ul\");\n\n  _renderArbitrary(items.map(function (item) {\n    return _jsxWrapper(function (_item$name) {\n      elementOpen(\"li\");\n\n      _renderArbitrary(_item$name);\n\n      return elementClose(\"li\");\n    }, [item.name]);\n  }));\n\n  return elementClose(\"ul\");\n}\n```\n\n```javascript\n// Enabled\nfunction render() {\n  elementOpen(\"ul\");\n\n  items.map(function (item) {\n    elementOpen(\"li\");\n\n    _renderArbitrary(item.name);\n\n    return elementClose(\"li\");\n  });\n\n  return elementClose(\"ul\");\n}\n```\n\nTo do this, simply add the `fastRoot` option to the Incremental DOM\nplugin:\n\n```json\n{\n  \"plugins\": [[\n    \"transform-incremental-dom\", {\n      \"fastRoot\": true\n    }\n  ]]\n}\n```\n\n\nAlternatively, you may enable and disable this with inline comments:\n\n```jsx\nfunction render() {\n    /**\n     * Enable for this tree\n     * @incremental-dom enable-fastRoot\n     */\n    return \u003cdiv\u003e{\n      items.map(function(item) {\n        return \u003cli\u003e{item.name}\u003c/li\u003e;\n      })\n    }\u003c/div\u003e;\n}\n\n/**\n * Enable for everything under this function\n * @incremental-dom enable-fastRoot\n */\nfunction render() {\n    /**\n     * Disable fastroot for this tree\n     * @incremental-dom disable-fastRoot\n     */\n    return \u003cdiv\u003e{\n      items.map(function(item) {\n        return \u003cli\u003e{item.name}\u003c/li\u003e;\n      })\n    }\u003c/div\u003e;\n}\n```\n\n#### Components\n\nYou may enable the experimental `components` option so that JSX tags\nthat start with an upper case letter are passed as a reference to\nincremental DOM calls, instead of as a string. This can be useful when\nyour code implements components through these kind of calls, though\nthat's not done by incremental DOM automatically. Note that this will\nbreak unless you have code to handle it.\n\n\n```javascript\n// Disabled (default)\nfunction render() {\n  elementVoid(\"MyComponent\");\n}\n```\n\n```javascript\n// Enabled\nfunction render() {\n  elementVoid(MyComponent);\n}\n```\n\nTo do this, simply add the `components` option to the Incremental DOM\nplugin:\n\n```json\n{\n  \"plugins\": [[\n    \"transform-incremental-dom\", {\n      \"components\": true\n    }\n  ]]\n}\n```\n\n#### Auto Importing Incremental DOM\n\nBy deafult, `babel-plugin-transform-incremental-dom` expects any necessary\nIncremental DOM methods to already imported and in-scope:\n\n```javascript\n// Disabled (default)\n\n// Manually managed imports\nimport { elementOpen, elementClose, text } from \"incremental-dom\";\n\nfunction render() {\n  elementOpen(\"div\");\n  text(\"Hello World.\");\n  elementClose(\"div\");\n}\n```\n\nThis is a hassle if you suddenly use a spread attribute and don't\nremember to import `elementOpenStart`, `elementOpenEnd`, and `attr`\nmethods. And, `attr` and `text` are very generic names, leading to\nissues where you might redefine the variable in the rendering function,\nbreaking it.\n\nThis can be fixed entirely by auto-importing everything necessary from\nIncremental DOM module:\n\n```javascript\n// Enabled with `incremental-dom`\n\n// Auto generated import\nvar _incrementalDOM = require(\"incremental-dom\");\n\nfunction render() {\n  (0, _incrementalDOM.elementOpen)(\"div\");\n  (0, _incrementalDOM.text)(\"Hello World.\");\n  (0, _incrementalDOM.elementClose)(\"div\");\n}\n```\n\nTo do this, simply add the `moduleSource` option to the Incremental DOM\nplugin:\n\n```json\n{\n  \"plugins\": [[\n    \"transform-incremental-dom\", {\n      \"moduleSource\": \"incremental-dom\"\n    }\n  ]]\n}\n```\n\nAdditionally, the module source can be an absolute or relative path to\nthe module. If a relative path is used, it will be resolve relative to\nthe `process.cwd()` of the babel process.\n\n#### Skip Children\n\nSome templates do not control all the child elements of certain nodes,\nlike components. Incremental DOM supports such nodes using a \"skip\"\nchild. To support this, we identify a special skip attribute, which will\nnot contain any child nodes and will never clear the later-added\nchildren of the element.\n\n```javascript\nfunction render() {\n    // This node will neither create nor clear children.\n    return \u003cdiv __skip\u003e\n    \u003c/div\u003e;\n}\n```\n\n\nTo customize the attribute that signals a skip, simply add the\n`skipAttribute` option to the Incremental DOM plugin:\n\n```json\n{\n  \"plugins\": [[\n    \"transform-incremental-dom\", {\n      \"skipAttribute\": \"skip\"\n    }\n  ]]\n}\n```\n\n\n#### Runtime\n\nBy deafult, `babel-plugin-transform-incremental-dom` injects several helpers into\neach file as needed. When transforming multiple files with JSX, you can\navoid this helper duplication by specifying a runtime library to use\ninstead.\n\nThe runtime's required functions are:\n\n- `jsxWrapper`\n\n  To prevent iDOM's incremental nature from screwing up our beautiful\n  JSX syntax, certain elements rendering functions must be wrapped\n  evaluated at a later time. The element will be passed into\n  `jsxWrapper`, along with an array of any (if any) arguments needed to\n  render the contained JSX element.\n\n  Note it is not `jsxWrapper`'s responsibility to create the JSX\n  rendering function, merely to mark the passed in function as a lazy\n  evaluation. Here, we return a special `__jsxDOMWrapper` struct with\n  the needed information.\n\n  ```javascript\n  runtime.jsxWrapper = function(elementFn, args) {\n    return {\n      __jsxDOMWrapper: true,\n      func: elementFn,\n      args: args\n    };\n  }\n  ```\n\n- `renderArbitrary`\n\n  To render child elements correctly, we'll need to be able to identify\n  them. `renderArbitrary` receives a `child`, and must call the\n  appropriate action. For string and numbers, that's to call\n  `IncrementalDOM#text`. For lazy evaluation JSX functions, that's to\n  invoke the closure. For arrays, that's to render every element. And\n  for objects, that's to render every property.\n\n  Note that we identify lazy JSX functions by the `__jsxDOMWrapper`\n  struct we created inside the `jsxWrapper` runtime function.\n\n  ```javascript\n  runtime.renderArbitrary = function _renderArbitrary(child) {\n    var type = typeof child;\n    if (type === \"number\" || (type === string || type === 'object' \u0026\u0026 child instanceof String)) {\n      iDOM.text(child);\n    } else if (Array.isArray(child)) {\n      child.forEach(_renderArbitrary);\n    } else if (type === \"object\") {\n      if (child.__jsxDOMWrapper) {\n        var func = child.func, args = child.args;\n        if (args) {\n          func.apply(this, args);\n        } else {\n          func();\n        }\n      } else if (String(child) === \"[object Object]\") {\n        _forOwn(child, _renderArbitrary);\n      }\n    }\n  }\n  ```\n\n- `spreadAttribute`\n\n  To set every attribute inside a SpreadAttribute, we'll need to iterate\n  over every property and determine if it's an _own_ property. If so,\n  call `IncrementalDOM#attr` to set it.\n\n  ```javascript\n  runtime.spreadAttribute = function _spreadAttribute(spread) {\n    for (var prop in spread) {\n      if (Object.prototype.hasOwn.call(spread, prop)) {\n        iDOM.attr(prop, spread[prop]);\n      }\n    }\n  }\n  ```\n\nTo do this, simply add the `runtimeModuleSource` option to the\nIncremental DOM plugin:\n\n```json\n{\n  \"plugins\": [[\n    \"transform-incremental-dom\", {\n      \"runtimeModuleSource\": \"iDOMHelpers\"\n    }\n  ]]\n}\n```\n\nAdditionally, the runtime module source can be an absolute or relative\npath to the module. If a relative path is used, it will be resolve\nrelative to the `process.cwd()` of the babel process.\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjridgewell%2Fbabel-plugin-transform-incremental-dom","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjridgewell%2Fbabel-plugin-transform-incremental-dom","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjridgewell%2Fbabel-plugin-transform-incremental-dom/lists"}