Skip to content

Commit 405b6a2

Browse files
committed
remove all runtime usages of NPM
With recent changes to the custom component interface, it's now possible to remove all runtime reliance on NPM. Doing so has many virtuous knock-on effects: 1. Removal of large chunks of code 2. Greatly simplifies how users dynamically experiment with React component libraries, because their usage no longer requires a build step. Instead they can be loaded in the browser from a CDN that distributes ESM modules. 3. The built-in client code needs to make fewer assumption about where static resources are located, and as a result, it's also easier to coordinate the server and client code. 4. Alternate client implementations benefit from this simplicity. Now, it's possible to install idom-client-react normally and write a loadImportSource() function that looks for route serving the contents of IDOM_WEB_MODULES_DIR. This change includes large breaking changes: - The CLI is being removed as it won't be needed any longer - The idom.client is being removed in favor of a stripped down idom.web module - The IDOM_CLIENT_BUILD_DIR config option will no longer exist and a new IDOM_WEB_MODULES_DIR which only contains dynamically linked web modules. While this new directory's location is configurable, it is meant to be transient and should not be re-used across sessions. The new idom.web module takes a simpler approach to constructing import sources and expands upon the logic for resolving imports by allowing exports from URLs to be discovered too. Now, that IDOM isn't using NPM to dynamically install component libraries idom.web instead creates JS modules from template files and links them into IDOM_WEB_MODULES_DIR. These templates ultimately direct the browser to load the desired library from a CDN.
1 parent b976453 commit 405b6a2

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

70 files changed

+456
-1677
lines changed

MANIFEST.in

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,4 @@
11
recursive-include src/idom *
2-
recursive-exclude src/idom/client/app/node_modules *
3-
recursive-exclude src/idom/client/app/web_modules *
4-
recursive-exclude src/idom/client/build *
2+
recursive-exclude src/idom/client/node_modules *
53
include requirements/prod.txt
64
include requirements/extras.txt

docs/Dockerfile

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ ADD README.md ./
2828

2929
RUN pip install -e .[all]
3030

31-
ENV IDOM_DEBUG_MODE=1
32-
ENV IDOM_CLIENT_BUILD_DIR=./build
33-
3431
RUN python -m idom install htm victory semantic-ui-react @material-ui/core
3532

3633
# Build the Docs
@@ -44,4 +41,5 @@ RUN sphinx-build -b html docs/source docs/build
4441
# Define Entrypoint
4542
# -----------------
4643
ENV PORT 5000
44+
ENV IDOM_DEBUG_MODE=1
4745
CMD python docs/main.py
Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
import idom
22

33

4-
material_ui = idom.install("@material-ui/core", fallback="loading...")
4+
mui = idom.web.module_from_template("react", "@material-ui/core", fallback="⌛")
5+
Button = idom.web.export(mui, "Button")
56

67
idom.run(
78
idom.component(
8-
lambda: material_ui.Button(
9-
{"color": "primary", "variant": "contained"}, "Hello World!"
10-
)
9+
lambda: Button({"color": "primary", "variant": "contained"}, "Hello World!")
1110
)
1211
)

docs/source/examples/material_ui_button_on_click.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@
33
import idom
44

55

6-
material_ui = idom.install("@material-ui/core", fallback="loading...")
6+
mui = idom.web.module_from_template("react", "@material-ui/core", fallback="⌛")
7+
Button = idom.web.export(mui, "Button")
78

89

910
@idom.component
1011
def ViewButtonEvents():
1112
event, set_event = idom.hooks.use_state(None)
1213

1314
return idom.html.div(
14-
material_ui.Button(
15+
Button(
1516
{
1617
"color": "primary",
1718
"variant": "contained",

docs/source/examples/material_ui_slider.py

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,16 @@
33
import idom
44

55

6-
material_ui = idom.install("@material-ui/core", fallback="loading...")
6+
mui = idom.web.module_from_template("react", "@material-ui/core", fallback="⌛")
7+
Slider = idom.web.export(mui, "Slider")
78

89

910
@idom.component
1011
def ViewSliderEvents():
1112
(event, value), set_data = idom.hooks.use_state((None, 50))
1213

1314
return idom.html.div(
14-
material_ui.Slider(
15+
Slider(
1516
{
1617
"color": "primary" if value < 50 else "secondary",
1718
"step": 10,

docs/source/examples/super_simple_chart.py

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
11
from pathlib import Path
22

33
import idom
4+
from idom.config import IDOM_WED_MODULES_DIR
45

56

6-
path_to_source_file = Path(__file__).parent / "super_simple_chart.js"
7-
ssc = idom.Module("super-simple-chart", source_file=path_to_source_file)
8-
7+
file = Path(__file__).parent / "super_simple_chart.js"
8+
ssc = idom.web.module_from_file("super-simple-chart", file, fallback="⌛")
9+
SuperSimpleChart = idom.web.export(ssc, "SuperSimpleChart")
910

1011
idom.run(
1112
idom.component(
12-
lambda: ssc.SuperSimpleChart(
13+
lambda: SuperSimpleChart(
1314
{
1415
"data": [
1516
{"x": 1, "y": 2},

docs/source/examples/victory_chart.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
import idom
22

33

4-
victory = idom.install("victory", fallback="loading...")
4+
victory = idom.web.module_from_template("react", "victory", fallback="⌛")
5+
VictoryBar = idom.web.export(victory, "VictoryBar")
6+
57
bar_style = {"parent": {"width": "500px"}, "data": {"fill": "royalblue"}}
6-
idom.run(idom.component(lambda: victory.VictoryBar({"style": bar_style})))
8+
idom.run(idom.component(lambda: VictoryBar({"style": bar_style})))

docs/source/installation.rst

Lines changed: 0 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -55,97 +55,5 @@ table below:
5555
* - ``flask``
5656
- `Flask <https://palletsprojects.com/p/flask/>`__ as a :ref:`Layout Server`
5757

58-
* - ``dialect``
59-
- :ref:`Python Language Extension` for writing JSX-like syntax
60-
6158
* - ``all``
6259
- All the features listed above (not usually needed)
63-
64-
65-
Python Language Extension
66-
-------------------------
67-
68-
IDOM includes an import-time transpiler for writing JSX-like syntax in a ``.py`` file!
69-
70-
.. code-block:: python
71-
72-
# dialect=html
73-
from idom import html
74-
75-
message = "hello world!"
76-
attrs = {"height": "10px", "width": "10px"}
77-
model = html(f"<div ...{attrs}><p>{message}</p></div>")
78-
79-
assert model == {
80-
"tagName": "div",
81-
"attributes": {"height": "10px", "width": "10px"},
82-
"children": [{"tagName": "p", "children": ["hello world!"]}],
83-
}
84-
85-
With Jupyter and IPython support:
86-
87-
.. code-block:: python
88-
89-
%%dialect html
90-
from idom import html
91-
assert html(f"<div/>") == {"tagName": "div"}
92-
93-
That you can install with ``pip``:
94-
95-
.. code-block::
96-
97-
pip install idom[dialect]
98-
99-
100-
Usage
101-
.....
102-
103-
1. Import ``idom`` in your application's ``entrypoint.py``
104-
105-
2. Import ``your_module.py`` with a ``# dialect=html`` header comment.
106-
107-
3. Inside ``your_module.py`` import ``html`` from ``idom``
108-
109-
4. Run ``python entrypoint.py`` from your console.
110-
111-
So here's the files you should have set up:
112-
113-
.. code-block:: text
114-
115-
project
116-
|- entrypoint.py
117-
|- your_module.py
118-
119-
The contents of ``entrypoint.py`` should contain:
120-
121-
.. code-block::
122-
123-
import idom # this needs to be first!
124-
import your_module
125-
126-
While ``your_module.py`` should contain the following:
127-
128-
.. code-block::
129-
130-
# dialect=html
131-
from idom import html
132-
assert html(f"<div/>") == {"tagName": "div"}
133-
134-
And that's it!
135-
136-
137-
How It Works
138-
............
139-
140-
Once ``idom`` has been imported at your application's entrypoint, any following modules
141-
imported with a ``# dialect=html`` header comment get transpiled just before they're
142-
executed. This is accomplished by using Pyalect_ to hook a transpiler into Pythons
143-
import system. The :class:`~idom.dialect.HtmlDialectTranspiler` implements Pyalect_'s
144-
:class:`~pyalect.dialect.Transpiler` interface using some tooling from htm.py_.
145-
146-
147-
.. Links
148-
.. =====
149-
150-
.. _Pyalect: https://pyalect.readthedocs.io/en/latest/
151-
.. _htm.py: https://github.com/jviide/htm.py

noxfile.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,3 @@ def install_idom_dev(session: Session, extras: str = "stable") -> None:
205205
session.install("-e", f".[{extras}]")
206206
else:
207207
session.posargs.remove("--no-install")
208-
if "--no-restore" not in session.posargs:
209-
session.run("idom", "restore")
210-
else:
211-
session.posargs.remove("--no-restore")

requirements/check-types.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,4 @@ types-click
33
types-tornado
44
types-pkg-resources
55
types-flask
6+
types-requests

requirements/pkg-deps.txt

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
typing-extensions >=3.7.4
22
mypy-extensions >=0.4.3
33
anyio >=3.0
4-
async_exit_stack >=1.0.1; python_version<"3.7"
54
jsonpatch >=1.26
6-
typer >=0.3.2
7-
click-spinner >=0.1.10
85
fastjsonschema >=2.14.5
9-
rich >=9.13.0
10-
appdirs >=1.4.4
6+
requests >=2.0

requirements/pkg-extras.txt

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,3 @@ selenium
1919

2020
# extra=matplotlib
2121
matplotlib
22-
23-
# extra=dialect
24-
htm
25-
pyalect
26-
tagged

setup.py

Lines changed: 1 addition & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,6 @@ def list2cmdline(cmd_list):
6363
}
6464

6565

66-
# -----------------------------------------------------------------------------
67-
# CLI Entrypoints
68-
# -----------------------------------------------------------------------------
69-
70-
71-
package["entry_points"] = {
72-
"console_scripts": ["idom = idom.__main__:main"],
73-
}
74-
75-
7666
# -----------------------------------------------------------------------------
7767
# Requirements
7868
# -----------------------------------------------------------------------------
@@ -129,7 +119,7 @@ class Command(cls):
129119
def run(self):
130120
log.info("Installing Javascript...")
131121
try:
132-
js_dir = str(package_dir / "client" / "app")
122+
js_dir = str(package_dir / "client")
133123
npm = shutil.which("npm") # this is required on windows
134124
if npm is None:
135125
raise RuntimeError("NPM is not installed.")

src/idom/__init__.py

Lines changed: 2 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,7 @@
1010

1111
__author__ = "idom-team"
1212

13-
from . import config, log
14-
from .client.module import Import, Module, install
13+
from . import config, log, web
1514
from .core import hooks
1615
from .core.component import Component, component
1716
from .core.events import Events, event
@@ -23,21 +22,6 @@
2322
from .widgets.utils import hotswap, multiview
2423

2524

26-
# try to automatically setup the dialect's import hook
27-
try:
28-
import htm
29-
import pyalect
30-
import tagged
31-
except ImportError: # pragma: no cover
32-
pass
33-
else:
34-
from . import dialect
35-
36-
del pyalect
37-
del tagged
38-
del htm
39-
40-
4125
__all__ = [
4226
"run",
4327
"component",
@@ -51,8 +35,6 @@
5135
"server",
5236
"Ref",
5337
"vdom",
54-
"Module",
55-
"Import",
5638
"hotswap",
5739
"multiview",
5840
"html_to_vdom",
@@ -62,4 +44,5 @@
6244
"install",
6345
"log",
6446
"config",
47+
"web",
6548
]

src/idom/__main__.py

Lines changed: 0 additions & 5 deletions
This file was deleted.

src/idom/_option.py

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,12 @@
88
import os
99
from logging import getLogger
1010
from typing import Any, Callable, Generic, TypeVar, cast
11-
from weakref import WeakSet
1211

1312

1413
_O = TypeVar("_O")
1514
logger = getLogger(__name__)
1615

1716

18-
ALL_OPTIONS: WeakSet[Option[Any]] = WeakSet()
19-
20-
2117
class Option(Generic[_O]):
2218
"""An option that can be set using an environment variable of the same name"""
2319

@@ -35,7 +31,6 @@ def __init__(
3531
if name in os.environ:
3632
self._current = validator(os.environ[name])
3733
logger.debug(f"{self._name}={self.current}")
38-
ALL_OPTIONS.add(self)
3934

4035
@property
4136
def name(self) -> str:

0 commit comments

Comments
 (0)