Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(Template): Introduce template for react extensions #69

Merged
merged 36 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
36 commits
Select commit Hold shift + click to select a range
03207ea
Created first raw version of react extension
Pive01 Jun 25, 2024
a835f75
re-added previous template
Pive01 Jun 25, 2024
83b452d
Simply added anything in the build folder
Pive01 Jun 25, 2024
73d1e94
Fixed missing files
Pive01 Jun 25, 2024
db2e683
Simplified routing patterns
Pive01 Jun 25, 2024
4936f16
updated template
Pive01 Jun 27, 2024
aad8fe5
Updated base endpoint
Pive01 Jun 28, 2024
1fbf3a6
Modified cookiecutter to choose base route based on location
Pive01 Jul 2, 2024
4c58937
Added hot reloading to extension UI
Pive01 Jul 3, 2024
5c5f9f0
Fixed issue with wrong boolean value
Pive01 Jul 3, 2024
7a09a16
Updated README for react extension
Pive01 Jul 3, 2024
92e2c76
Updated template to use WebAppExtension class
Pive01 Jul 3, 2024
88be707
Removed unnecessary dependencies
Pive01 Jul 3, 2024
e6d348c
Added comment
Pive01 Jul 3, 2024
b026d1b
Moved templates to allow retro-compatibility
Pive01 Jul 3, 2024
a018dec
re-ordered template folders
Pive01 Jul 5, 2024
817a16e
Bit of adjustment to packaging and naming
Pive01 Jul 9, 2024
182cf2f
Added yarn install warning
Pive01 Jul 9, 2024
ec8914e
Updated package.json with new published package
Pive01 Jul 15, 2024
28306e3
Update README.md
maxhoheiser Jul 15, 2024
b148dcc
changed directory layout for react extension
Pive01 Jul 23, 2024
458931f
Apply suggestions from code review
Pive01 Jul 24, 2024
9560d22
Address some comments
Pive01 Jul 24, 2024
94c9637
Added .gitignore
Pive01 Jul 24, 2024
0510550
Addressed more comments
Pive01 Jul 24, 2024
5b8aa91
update requirements in base template
Pive01 Jul 24, 2024
8911b91
use pyproject.toml for react template
dominikschubert Jul 25, 2024
8517417
extend gitignore for react template
dominikschubert Jul 25, 2024
1067819
install dev version of localstack-core
dominikschubert Jul 25, 2024
0f3229f
Changed other templates from setup to pyproject
Pive01 Jul 26, 2024
900077e
Update templates/react/{{cookiecutter.project_slug}}/pyproject.toml
Pive01 Jul 26, 2024
b80cc5f
updated pyproject.toml
Pive01 Jul 26, 2024
e659844
Added checks for corepack / yarn stuff
Pive01 Jul 29, 2024
9f93c0c
added .pth for package discovery
Pive01 Jul 29, 2024
b0ced60
Merge remote-tracking branch 'origin/main' into react-template
thrau Aug 16, 2024
859faaf
reset changes to original template
thrau Aug 16, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions templates/basic/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Extension Template
==================

This is a [cookiecutter](https://github.com/cookiecutter/cookiecutter) template that is used when you invoke.

```console
localstack extensions dev new
```

It contains a simple python distribution config, and some boilerplate extension code.
11 changes: 11 additions & 0 deletions templates/basic/cookiecutter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"project_name": "My LocalStack Extension",
"project_short_description": "All the boilerplate you need to create a LocalStack extension.",
"project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '-') }}",
"module_name": "{{ cookiecutter.project_slug.replace('-', '_') }}",
"class_name": "{{ cookiecutter.project_name.replace('-', ' ').replace('_', ' ').title().replace(' ', '') }}",
"full_name": "Jane Doe",
"email": "jane@example.com",
"github_username": "janedoe",
"version": "0.1.0"
}
5 changes: 5 additions & 0 deletions templates/basic/{{cookiecutter.project_slug}}/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
.venv
dist
build
**/*.egg-info
.eggs
32 changes: 32 additions & 0 deletions templates/basic/{{cookiecutter.project_slug}}/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
VENV_BIN = python3 -m venv
Copy link
Member

Choose a reason for hiding this comment

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

same arguments as below in the react template

VENV_DIR ?= .venv
VENV_ACTIVATE = $(VENV_DIR)/bin/activate
VENV_RUN = . $(VENV_ACTIVATE)

venv: $(VENV_ACTIVATE)

$(VENV_ACTIVATE): setup.py setup.cfg
test -d .venv || $(VENV_BIN) .venv
$(VENV_RUN); pip install --upgrade pip setuptools plux
$(VENV_RUN); pip install -e .
touch $(VENV_DIR)/bin/activate

clean:
rm -rf .venv/
rm -rf build/
rm -rf .eggs/
rm -rf *.egg-info/

install: venv
$(VENV_RUN); python setup.py develop

dist: venv
$(VENV_RUN); python setup.py sdist bdist_wheel

publish: clean-dist venv dist
$(VENV_RUN); pip install --upgrade twine; twine upload dist/*

clean-dist: clean
rm -rf dist/

.PHONY: clean clean-dist dist install publish
34 changes: 34 additions & 0 deletions templates/basic/{{cookiecutter.project_slug}}/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{{ cookiecutter.project_name }}
===============================

{{ cookiecutter.project_short_description }}

## Install local development version

To install the extension into localstack in developer mode, you will need Python 3.10, and create a virtual environment in the extensions project.

In the newly generated project, simply run

```bash
make install
```

Then, to enable the extension for LocalStack, run

```bash
localstack extensions dev enable .
```

You can then start LocalStack with `EXTENSION_DEV_MODE=1` to load all enabled extensions:

```bash
EXTENSION_DEV_MODE=1 localstack start
```

## Install from GitHub repository

To distribute your extension, simply upload it to your github account. Your extension can then be installed via:

```bash
localstack extensions install "git+https://github.com/{{cookiecutter.github_username }}/{{ cookiecutter.project_slug }}/#egg={{ cookiecutter.project_slug }}"
```
22 changes: 22 additions & 0 deletions templates/basic/{{cookiecutter.project_slug}}/setup.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
[metadata]
Copy link
Member

Choose a reason for hiding this comment

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

same comments apply here of course as with the react template below

name = {{ cookiecutter.project_slug }}
version = {{ cookiecutter.version }}
summary = LocalStack Extension: {{ cookiecutter.project_name }}
url = https://github.com/{{ cookiecutter.github_username }}/{{ cookiecutter.project_slug }}
author = {{ cookiecutter.full_name }}
author_email = {{ cookiecutter.email }}
description = {{ cookiecutter.project_short_description }}
long_description = file: README.md
long_description_content_type = text/markdown; charset=UTF-8

[options]
zip_safe = False
packages = find:

[options.extras_require]
test=
localstack-core>=2.2

[options.entry_points]
localstack.extensions =
{{ cookiecutter.project_slug }} = {{ cookiecutter.module_name }}.extension:{{ cookiecutter.class_name }}
4 changes: 4 additions & 0 deletions templates/basic/{{cookiecutter.project_slug}}/setup.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
#!/usr/bin/env python
from setuptools import setup

setup()
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
name = "{{ cookiecutter.module_name }}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
from localstack.extensions.api import Extension, http, aws

class {{ cookiecutter.class_name }}(Extension):
name = "{{ cookiecutter.project_slug }}"

def on_extension_load(self):
print("MyExtension: extension is loaded")

def on_platform_start(self):
print("MyExtension: localstack is starting")

def on_platform_ready(self):
print("MyExtension: localstack is running")

def update_gateway_routes(self, router: http.Router[http.RouteHandler]):
pass

def update_request_handlers(self, handlers: aws.CompositeHandler):
pass

def update_response_handlers(self, handlers: aws.CompositeResponseHandler):
pass
10 changes: 10 additions & 0 deletions templates/react/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
Extension Template
==================

This is a [cookiecutter](https://github.com/cookiecutter/cookiecutter) template that is used when you invoke.

```console
localstack extensions dev new --template=react
```

It contains a simple python distribution config, and some boilerplate extension code.
11 changes: 11 additions & 0 deletions templates/react/cookiecutter.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
{
"project_name": "My LocalStack Extension",
"project_short_description": "All the boilerplate you need to create a LocalStack extension.",
"project_slug": "{{ cookiecutter.project_name.lower().replace(' ', '-') }}",
"module_name": "{{ cookiecutter.project_slug.replace('-', '_') }}",
"class_name": "{{ cookiecutter.project_name.replace('-', ' ').replace('_', ' ').title().replace(' ', '') }}",
"full_name": "Jane Doe",
"email": "jane@example.com",
"github_username": "janedoe",
"version": "0.1.0"
}
9 changes: 9 additions & 0 deletions templates/react/{{cookiecutter.project_slug}}/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
.venv
frontend/node_modules
frontend/.yarn
dist
build
**/*.egg-info
.eggs
__pycache__
*.pyc
56 changes: 56 additions & 0 deletions templates/react/{{cookiecutter.project_slug}}/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
VENV_BIN = python3 -m venv
VENV_DIR ?= .venv
VENV_ACTIVATE = $(VENV_DIR)/bin/activate
VENV_RUN = . $(VENV_ACTIVATE)
FRONTEND_FOLDER = frontend
BACKEND_FOLDER = backend


INFO_COLOR = \033[0;36m
NO_COLOR = \033[m

venv: $(VENV_ACTIVATE)

$(VENV_ACTIVATE):
test -d .venv || $(VENV_BIN) .venv
$(VENV_RUN); pip install --upgrade pip setuptools plux build wheel
$(VENV_RUN); pip install -e .[dev]
touch $(VENV_DIR)/bin/activate

clean: ## Clean the project
rm -rf .venv/
rm -rf build/
rm -rf .eggs/
rm -rf $(BACKEND_FOLDER)/*.egg-info/

install-backend: venv ## Install dependencies of the extension
$(VENV_RUN); python -m plux entrypoints

install-frontend: venv ## Install dependencies of the frontend
cd $(FRONTEND_FOLDER) && yarn install

build-frontend: # Build the React app
@if [ ! -d "$(FRONTEND_FOLDER)/node_modules" ]; then \
$(MAKE) install-frontend; \
fi
cd $(FRONTEND_FOLDER); rm -rf build && REACT_APP_DEVELOPMENT_ENVIRONMENT=false NODE_ENV=prod npm run build

start-frontend: ## Start the frontend in dev mode (hot reload)
cd $(FRONTEND_FOLDER); REACT_APP_DEVELOPMENT_ENVIRONMENT=true yarn start

install: venv install-backend install-frontend ## Install dependencies

dist: venv build-frontend ## Create distribution files
$(VENV_RUN); python -m build

publish: clean-dist venv dist ## Build and upload package to pypi
$(VENV_RUN); pip install --upgrade twine; twine upload dist/*

clean-dist: clean ## Remove dist folder
rm -rf dist/

help: ## Show this help
@echo Please specify a build target. The choices are:
@grep -E '^[0-9a-zA-Z_-]+:.*?## .*$$' $(MAKEFILE_LIST) | awk 'BEGIN {FS = ":.*?## "}; {printf "$(INFO_COLOR)%-30s$(NO_COLOR) %s\n", $$1, $$2}'

.PHONY: clean clean-dist dist install install-backend install-frontend build-frontend start-frontend publish venv
42 changes: 42 additions & 0 deletions templates/react/{{cookiecutter.project_slug}}/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{{ cookiecutter.project_name }}
===============================

{{ cookiecutter.project_short_description }}

## Install local development version

To install the extension into localstack in developer mode, you will need Python 3.10+, and create a virtual environment in the extensions project.
You will also need to install [yarn](https://yarnpkg.com/getting-started/install) as package manager if you haven't already
In the newly generated project, simply run

```bash
make install
```

Then, to enable the extension for LocalStack, run

```bash
localstack extensions dev enable .
```

You can then start LocalStack with `EXTENSION_DEV_MODE=1` to load all enabled extensions:

```bash
EXTENSION_DEV_MODE=1 localstack start
```

## Developing UI
With this template is generated also a UI made in react that is available at either {{ cookiecutter.project_name }}.localhost.localstack.cloud:4566/ or http://localhost.localstack.cloud:4566/_extension/{{ cookiecutter.project_name }}/.

There are a few make commands available that will help your journey with the UI:
- **build-frontend**: will build the react app into the frontend/build folder which will then be passed into the extension itself allowing the UI to be seen. Remember to always execute this command when you wish to see new changes when using the extension.
- **start-frontend**: will start a live server on port 3000 (by default) that will allow you to have hot reloading when developing locally outside the extension (it will also build the frontend)


## Install from GitHub repository

To distribute your extension, simply upload it to your github account. Your extension can then be installed via:

```bash
localstack extensions install "git+https://github.com/{{cookiecutter.github_username }}/{{ cookiecutter.project_slug }}/#egg={{ cookiecutter.project_slug }}"
```
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
name = "{{ cookiecutter.module_name }}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from localstack.http import route, Request, Response

from .. import static

class WebApp:
@route("/")
def index(self, request: Request, *args, **kwargs):
return Response.for_resource(static, "index.html")

@route("/<path:path>")
def index2(self, request: Request, path: str, **kwargs):
return Response.for_resource(static, path)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import logging
import typing as t

from localstack.extensions.patterns.webapp import WebAppExtension

from .api.web import WebApp

LOG = logging.getLogger(__name__)


class {{ cookiecutter.class_name }}(WebAppExtension):
name = "{{ cookiecutter.project_slug }}"

def __init__(self):
super().__init__(template_package_path=None)

def collect_routes(self, routes: list[t.Any]):
routes.append(WebApp())

Loading