Skip to content

Commit 8e3b0b1

Browse files
authored
ability to specify version in template + no more exports_default (#765)
* ability to specify react version in template * fix simple chart example * changelog + add dynamic default export * test template versioning
1 parent b0c7f93 commit 8e3b0b1

File tree

12 files changed

+54
-76
lines changed

12 files changed

+54
-76
lines changed

docs/source/about/changelog.rst

+8
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,14 @@ Unreleased
3636
- ``ServerFixture -> BackendFixture``
3737
- ``DisplayFixture.server -> DisplayFixture.backend``
3838

39+
- :pull:`765` - ``exports_default`` parameter is not longer required for
40+
``module_from_template`` when exporting ``default``.
41+
42+
**Added**
43+
44+
- :pull:`765` - ability to specify versions with module templates (e.g.
45+
``module_from_template("react@^17.0.0", ...)``).
46+
3947

4048
v0.38.1
4149
-------
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
import idom
1+
from idom import component, run, web
22

33

4-
mui = idom.web.module_from_template("react", "@material-ui/core@^5.0", fallback="⌛")
5-
Button = idom.web.export(mui, "Button")
6-
7-
idom.run(
8-
idom.component(
9-
lambda: Button({"color": "primary", "variant": "contained"}, "Hello World!")
10-
)
4+
mui = web.module_from_template(
5+
"react@^17.0.0",
6+
"@material-ui/[email protected]",
7+
fallback="⌛",
118
)
9+
Button = web.export(mui, "Button")
10+
11+
12+
@component
13+
def HelloWorld():
14+
return Button({"color": "primary", "variant": "contained"}, "Hello World!")
15+
16+
17+
run(HelloWorld)

docs/source/guides/escape-hatches/_examples/material_ui_button_on_click.py

+5-1
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
import idom
44

55

6-
mui = idom.web.module_from_template("react", "@material-ui/core@^5.0", fallback="⌛")
6+
mui = idom.web.module_from_template(
7+
"react@^17.0.0",
8+
"@material-ui/[email protected]",
9+
fallback="⌛",
10+
)
711
Button = idom.web.export(mui, "Button")
812

913

docs/source/guides/escape-hatches/_examples/super_simple_chart/super-simple-chart.js

+3-4
Original file line numberDiff line numberDiff line change
@@ -48,10 +48,9 @@ function makePath(props, domain, data, options) {
4848
const getSvgX = (x) => ((x - xMin) / (xMax - xMin)) * width;
4949
const getSvgY = (y) => height - ((y - yMin) / (yMax - yMin)) * height;
5050

51-
let pathD = "M " + getSvgX(data[0].x) + " " + getSvgY(data[0].y) + " ";
52-
pathD += data.map((point, i) => {
53-
return "L " + getSvgX(point.x) + " " + getSvgY(point.y) + " ";
54-
});
51+
let pathD =
52+
`M ${getSvgX(data[0].x)} ${getSvgY(data[0].y)} ` +
53+
data.map(({ x, y }, i) => `L ${getSvgX(x)} ${getSvgY(y)}`).join(" ");
5554

5655
return html`<path
5756
d="${pathD}"

docs/source/reference/_examples/network_graph.py

-2
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,8 @@
44

55

66
react_cytoscapejs = idom.web.module_from_template(
7-
# we need to use this template because react-cytoscapejs uses a default export
87
"react",
98
"react-cytoscapejs",
10-
exports_default=True,
119
fallback="⌛",
1210
)
1311
Cytoscape = idom.web.export(react_cytoscapejs, "default")

src/idom/web/module.py

+6-10
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,6 @@ def module_from_template(
7979
package: str,
8080
cdn: str = "https://esm.sh",
8181
fallback: Optional[Any] = None,
82-
exports_default: bool = False,
8382
resolve_exports: bool = IDOM_DEBUG_MODE.current,
8483
resolve_exports_depth: int = 5,
8584
unmount_before_update: bool = False,
@@ -93,7 +92,7 @@ def module_from_template(
9392
9493
This approach is not recommended for use in a production setting because the
9594
framework templates may use unpinned dependencies that could change without
96-
warning.cIt's best to author a module adhering to the
95+
warning. It's best to author a module adhering to the
9796
:ref:`Custom Javascript Component` interface instead.
9897
9998
**Templates**
@@ -110,8 +109,6 @@ def module_from_template(
110109
Where the package should be loaded from. The CDN must distribute ESM modules
111110
fallback:
112111
What to temporarilly display while the module is being loaded.
113-
exports_default:
114-
Whether the module has a default export.
115112
resolve_imports:
116113
Whether to try and find all the named exports of this module.
117114
resolve_exports_depth:
@@ -122,6 +119,9 @@ def module_from_template(
122119
Using this option has negative performance consequences since all DOM
123120
elements must be changed on each render. See :issue:`461` for more info.
124121
"""
122+
template_name, _, template_version = template.partition("@")
123+
template_version = "@" + template_version if template_version else ""
124+
125125
# We do this since the package may be any valid URL path. Thus we may need to strip
126126
# object parameters or query information so we save the resulting template under the
127127
# correct file name.
@@ -130,17 +130,13 @@ def module_from_template(
130130
# downstream code assumes no trailing slash
131131
cdn = cdn.rstrip("/")
132132

133-
template_file_name = (
134-
template
135-
+ (".default" if exports_default else "")
136-
+ module_name_suffix(package_name)
137-
)
133+
template_file_name = template_name + module_name_suffix(package_name)
138134

139135
template_file = Path(__file__).parent / "templates" / template_file_name
140136
if not template_file.exists():
141137
raise ValueError(f"No template for {template_file_name!r} exists")
142138

143-
variables = {"PACKAGE": package, "CDN": cdn}
139+
variables = {"PACKAGE": package, "CDN": cdn, "VERSION": template_version}
144140
content = Template(template_file.read_text()).substitute(variables)
145141

146142
return module_from_string(

src/idom/web/templates/react.default.js

-48
This file was deleted.

src/idom/web/templates/react.js

+15-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,20 @@
11
export * from "$CDN/$PACKAGE";
22

3-
import * as React from "$CDN/react";
4-
import * as ReactDOM from "$CDN/react-dom";
3+
import * as React from "$CDN/react$VERSION";
4+
import * as ReactDOM from "$CDN/react-dom$VERSION";
5+
6+
export default ({ children, ...props }) => {
7+
const [{ component }, setComponent] = React.useState({});
8+
React.useEffect(() => {
9+
import("$CDN/$PACKAGE").then((module) => {
10+
// dynamically load the default export since we don't know if it's exported.
11+
setComponent({ component: module.default });
12+
});
13+
});
14+
return component
15+
? React.createElement(component, props, ...(children || []))
16+
: null;
17+
};
518

619
export function bind(node, config) {
720
return {
File renamed without changes.
File renamed without changes.
File renamed without changes.

tests/test_web/test_module.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,9 @@ def test_module_from_template_where_template_does_not_exist():
8383

8484

8585
async def test_module_from_template(display: DisplayFixture):
86-
victory = idom.web.module_from_template("react", "[email protected]")
86+
victory = idom.web.module_from_template("[email protected]", "[email protected]")
87+
88+
assert "[email protected]" in victory.file.read_text()
8789
VictoryBar = idom.web.export(victory, "VictoryBar")
8890
await display.show(VictoryBar)
8991

0 commit comments

Comments
 (0)