Skip to content
This repository was archived by the owner on Jun 21, 2024. It is now read-only.

Comments

Frontend toolchain setup and some basic map widgets#4

Merged
chrisdevereux merged 16 commits intomainfrom
frontend-setup
Nov 24, 2021
Merged

Frontend toolchain setup and some basic map widgets#4
chrisdevereux merged 16 commits intomainfrom
frontend-setup

Conversation

@chrisdevereux
Copy link
Contributor

@chrisdevereux chrisdevereux commented Nov 23, 2021

Description

This PR sets up the frontend build system and adds the first feature. There's quite a lot here – happy to walk through it.

In a little more detail, we add the following:

  • Frontend build system setup using vite. This is used to build the bundled js – doesn't impose any constraints on the build system used by the application.
  • Sets up jest and some helpers for unit testing stimulus controllers
  • Adds a helper to setup the stimulus app and load controllers on-demand (lazily, when first referenced on a page).
  • Adds, documents and tests stimulus controllers for:
    • Rendering a mapbox map widget
    • Adding datasources and layers 'over the wire' in html.
    • A more general framework for hooking into the mapbox widget via additional stimulus controllers.
  • Adds, documents and tests django template tags for configuring and rendering a map widget without having to know about stimulus syntax.
  • Adds an example app that demonstrates the map widget.
  • Configures the CI to lint and test frontend code.

Although the APIs are all documented, we're missing a more high-level architectural overview, with information about how to use and extend this setup. I'm happy to add this onto this PR if wanted, but haven't yet as I'd like a bit of feedback on what you'd like explained.

How Can It Be Tested?

  • Follow the dev setup instructions.
  • Switch to this branch, run yarn and poetry install to pull in dependencies.
  • Run the 'Run example app' task in vscode.
  • Visit http://localhost:8000/geo/map/ and confirm that a map is rendered with a data-driven layer rendered on top.

Screenshots (if appropriate):

Screenshot 2021-11-23 at 15 09 06

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation change

Checklist:

  • I have documented all new methods using google docstring format.
  • I have added type annotations to any public API methods.
  • I have updated any relevant high-level documentation.
  • I have added a usage example to the example app if relevant.
  • I have written tests covering all new changes.

Copy link
Member

@conatus conatus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this is cool. If we could put all dependencies in the package manager, this could be rolled out.

I'm a bit in two minds about using Vite. The more well known bundler is obviously Webpack. When building a library one wants to consider such things. However, if a Webpack build breaks I am often at a complete loss how to fix it. Probably more of a loss than some new technology I don't know. So going to roll the dice on this one, in the understanding that at some point we may want to switch it around.

I don't think anyone will come to this library and think "no, not for me, doesn't use Webpack" and turn elsewhere. Feel free to respond on this PR world if I am wrong!


<script
type="module"
src="https://cdn.skypack.dev/@hotwired/turbo"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it better to use the bundler for these libraries now we have the bundler?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be clear, this is for the example/desk-testing app, so has no impact on the library itself. Although, agree – we should bundle it so that you can desk-test without an internet connection.

</script>
{% vite_hmr_client %} {% vite_asset 'example/frontend/main.ts' %}

<link
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Though I do think Bootstrap should be in the mix here, to keep the commit history clean, I really think that it makes sense to not include it in this commit. What do you think?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just for the example app. Mostly just so we have access to the util classes and components when demonstrating the features. We're not adding any kind of dependency to the library (at this point – not sure whether we do or not longer term)

Copy link
Member

@conatus conatus Nov 24, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Understood. Go with what you think is best for desk testing this then loop me back in to give it the digital nod.

"dependencies": {},
"devDependencies": {
"@hotwired/stimulus": "^3.0.1",
"@hotwired/turbo": "^7.0.1",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So this is included in the template and in the bundler. Could we include it in one or the other? Seems only right to do so.

@chrisdevereux
Copy link
Contributor Author

I think this is cool. If we could put all dependencies in the package manager, this could be rolled out.

We actually don't have any dependencies. Everything listed in devDependencies is one of:

  • A peer dependency (and listed in that section of package.json)
  • Build tooling
  • In the case of smaller dependencies, built into the library's js bundle.

I've gone for the last one because it reduces the api surface area (/scope for dependency hell) and has a minimal effect on the built bundle size. Open to reconsidering that approach though. I know people have differing opinions on this.

I'm a bit in two minds about using Vite. The more well known bundler is obviously Webpack. When building a library one wants to consider such things.

If it helps, Vite's production build mode wraps rollup.js, which is generally preferred over webpack for libraries.

(although the main reason I'm using it here is because it's so much quicker in dev mode)

@chrisdevereux chrisdevereux merged commit 43fc2b3 into main Nov 24, 2021
@chrisdevereux chrisdevereux deleted the frontend-setup branch November 24, 2021 16:27
Copy link
Member

@janbaykara janbaykara left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think Vite is a good choice to be honest! And in any case, as this is a library, bundling for userland will presumably result in plain file assets for hoovering up by Django's collectstatic command anyway. So the debate over bundler here is mainly for package developers which is a small crowd. Don't see too much controversy.

It'd be nice if MAPBOX_PUBLIC_API_KEY and MAPBOX_DEFAULT_STYLE were documented, for end users to use! Perhaps these could be auto-bundled with local.py, or an "env variables" section of the docs added.

Comment on lines +1 to +33
from typing import Any, List

from django.urls import path
from django.views.generic import TemplateView


class MapExampleView(TemplateView):
template_name = "pyck/geo/examples/map_example.html"

@property
def sources(self):
return {
"mapbox-terrain": {
"type": "vector",
"url": "mapbox://mapbox.mapbox-terrain-v2",
}
}

@property
def layers(self):
return [
{
"id": "terrain-data",
"type": "line",
"source": "mapbox-terrain",
"source-layer": "contour",
"layout": {"line-join": "round", "line-cap": "round"},
"paint": {"line-color": "#ff69b4", "line-width": 1},
}
]


urlpatterns: List[Any] = [path("map/", MapExampleView.as_view())]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In a future release, we should try to include more domain-specific examples. For mapping, we could do something like a doorknocking app showing contacted addresses or somesuch.

Comment on lines +1 to +11
<slot
data-controller="{{controller}}"
data-map-target="config"
{% for key, value in values.items %}
{% if value %}data-{{controller}}-{{key}}-value="{{value}}"{% endif %}
{% endfor %}
{% for key, value in attributes.items %}
{% if value %}{{key}}="{{value}}"{% endif %}
{% endfor %}
>
</slot>
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No version of Internet Explorer supports the slot tag, but presumably it will will break the page rendering?

Comment on lines +35 to +41
private apiKeyValue!: string;
private styleValue!: string;
private centerValue!: string;
private zoomValue!: number;

private canvasTarget!: HTMLElement;
private configTargets!: HTMLElement[];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's annoying that the Stimulus library can't somehow monkeypatch the types onto the class automatically!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants