Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
19 changes: 13 additions & 6 deletions .github/workflows/aws-proxy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,17 @@ jobs:
with:
python-version: '3.13'

- name: Use Node.js
uses: actions/setup-node@v3
with:
node-version: 20

- name: Enable Corepack and set Yarn version
run: |
corepack enable
corepack prepare yarn@3.2.3 --activate
shell: bash

- name: Set up Terraform CLI
uses: hashicorp/setup-terraform@v2

Expand All @@ -37,11 +48,8 @@ jobs:
docker pull localstack/localstack-pro &
docker pull public.ecr.aws/lambda/python:3.8 &

# install latest CLI packages (dev releases)
pip install --upgrade --pre localstack localstack-ext

# TODO remove
mkdir ~/.localstack; echo '{"token":"test"}' > ~/.localstack/auth.json
# install latest CLI packages
pip install --upgrade localstack localstack-ext

# install dependencies
sudo apt-get update
Expand All @@ -52,7 +60,6 @@ jobs:
(
make install
. .venv/bin/activate
pip install --upgrade --pre localstack localstack-ext
make build
make enable
)
Expand Down
3 changes: 3 additions & 0 deletions aws-proxy/.gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
*.tfstate*
.terraform*
node_modules
static
.yarn/
5 changes: 2 additions & 3 deletions aws-proxy/MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,3 +1,2 @@
recursive-include aws_proxy *.html
recursive-include aws_proxy *.js
recursive-include aws_proxy *.png
include pyproject.toml
recursive-exclude aws_proxy/frontend *
39 changes: 31 additions & 8 deletions aws-proxy/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -4,16 +4,13 @@ VENV_ACTIVATE = $(VENV_DIR)/bin/activate
VENV_RUN = . $(VENV_ACTIVATE)
TEST_PATH ?= tests
PIP_CMD ?= pip
FRONTEND_FOLDER = aws_proxy/frontend
COREPACK_EXISTS := $(shell command -v corepack)
YARN_EXISTS := $(shell command -v yarn)

usage: ## Show this help
@grep -Fh "##" $(MAKEFILE_LIST) | grep -Fv fgrep | sed -e 's/:.*##\s*/##/g' | awk -F'##' '{ printf "%-25s %s\n", $$1, $$2 }'

install: ## Install dependencies
test -d .venv || $(VENV_BIN) .venv
$(VENV_RUN); pip install -e .
$(VENV_RUN); pip install -e .[test]
touch $(VENV_DIR)/bin/activate

clean: ## Clean up
rm -rf .venv/
rm -rf build/
Expand All @@ -29,10 +26,10 @@ lint: ## Run code linter to check code style
test: ## Run tests
$(VENV_RUN); python -m pytest $(PYTEST_ARGS) $(TEST_PATH)

entrypoints: ## Generate plugin entrypoints for Python package
entrypoints: build-frontend ## Generate plugin entrypoints for Python package
$(VENV_RUN); python -m plux entrypoints

build: entrypoints ## Build the extension
build: build-frontend entrypoints ## Build the extension
$(VENV_RUN); python -m build --no-isolation . --outdir build
@# make sure that the entrypoints are contained in the dist folder and are non-empty
@test -s localstack_extension_aws_proxy.egg-info/entry_points.txt || (echo "Entrypoints were not correctly created! Aborting!" && exit 1)
Expand All @@ -45,6 +42,32 @@ enable: $(wildcard ./build/localstack_extension_aws_proxy-*.tar.gz) ## Enable t
publish: clean-dist venv dist
$(VENV_RUN); pip install --upgrade twine; twine upload dist/*

check-frontend-deps:
@if [ -z "$(YARN_EXISTS)" ]; then \
npm install --global yarn; \
fi
@if [ -z "$(COREPACK_EXISTS)" ]; then \
npm install -g corepack; \
fi

install-frontend: check-frontend-deps ## 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 && NODE_ENV=prod npm run build

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

install: install-frontend ## Install dependencies
test -d .venv || $(VENV_BIN) .venv
$(VENV_RUN); pip install -e .
$(VENV_RUN); pip install -e .[test]
touch $(VENV_DIR)/bin/activate

clean-dist: clean
rm -rf dist/

Expand Down
99 changes: 99 additions & 0 deletions aws-proxy/aws_proxy/frontend/.esbuild/esbuild.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
/* eslint-disable global-require */

const esbuild = require('esbuild');
const path = require('path');

const SvgrPlugin = require('esbuild-plugin-svgr');
const CopyPlugin = require('esbuild-plugin-copy').default;
const CleanPlugin = require('esbuild-plugin-clean').default;
const { NodeModulesPolyfillPlugin } = require('@esbuild-plugins/node-modules-polyfill');

const packageJson = require('../package.json');
const HtmlPlugin = require('./plugins/html');
const { writeFileSync } = require('fs');

const CURRENT_ENV = process.env.NODE_ENV || 'development.local';
const BUILD_PATH = path.join(__dirname, '..', '..', 'server', 'static');

const BUILD_CONFIG = {
entryPoints: [
path.join(__dirname, '..', 'src', 'index.tsx'),
path.join(__dirname, '..', 'src', 'index.html'),
],
assetNames: '[name]-[hash]',
entryNames: '[name]-[hash]',
outdir: BUILD_PATH,
bundle: true,
minify: !CURRENT_ENV.includes('development.local'),
sourcemap: true,
target: 'es2020',
metafile: true,
// splitting: true,
// set in case file loader is added below
plugins: [
CleanPlugin({
patterns: [`${BUILD_PATH}/*`, `!${BUILD_PATH}/index.html`],
sync: true,
verbose: false,
options: {
force: true
}
}),
SvgrPlugin({
prettier: false,
svgo: false,
svgoConfig: {
plugins: [{ removeViewBox: false }],
},
titleProp: true,
ref: true,
}),
CopyPlugin({
copyOnStart: true,
// https://github.com/LinbuduLab/nx-plugins/issues/57
assets: [
{
from: ['./public/*'],
to: ['./'],
},
],
}),
NodeModulesPolyfillPlugin(),
HtmlPlugin({
filename: path.join(BUILD_PATH, 'index.html'),
env: true,
}),
],
inject: [path.join(__dirname, 'esbuild.shims.js')],
define: {
// Define replacements for env vars starting with `REACT_APP_`
...Object.entries(process.env).reduce(
(memo, [name, value]) => name.startsWith('REACT_APP_') ?
{ ...memo, [`process.env.${name}`]: JSON.stringify(value) } :
memo,
{},
),
'process.cwd': 'dummyProcessCwd',
global: 'window',
},
external: [
...Object.keys(packageJson.devDependencies || {}),
],
loader: {
'.md': 'text',
'.gif': 'dataurl',
}
};

const build = async (overrides = {}) => {
try {
await esbuild.build({ ...BUILD_CONFIG, ...overrides });
writeFileSync(path.join(BUILD_PATH, '__init__.py'),'')
console.log('done building');
} catch (e) {
console.error(e);
process.exit(1);
}
};

module.exports = { build };
7 changes: 7 additions & 0 deletions aws-proxy/aws_proxy/frontend/.esbuild/esbuild.shims.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as React from 'react';

export { React };

export function dummyProcessCwd() {
return '';
};
11 changes: 11 additions & 0 deletions aws-proxy/aws_proxy/frontend/.esbuild/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
const { build, serve } = require('./esbuild.config');

(async () => {
if (process.argv.includes('--serve')) {
await serve();
} else if (process.argv.includes('--watch')) {
await build({ watch: true });
} else {
await build();
}
})();
84 changes: 84 additions & 0 deletions aws-proxy/aws_proxy/frontend/.esbuild/plugins/html/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
const fs = require('fs');
const path = require('path');
const crypto = require('crypto');

/**
* @param {object} config
* @param {string} config.filename - HTML file to process and override
* @param {boolean} config.env - Whether to replace env vars or not (default - `false`)
* @param {string} config.envPrefix - Limit env vars to pick (default - `REACT_APP_`)
*/
const HtmlPlugin = (config) => ({
name: 'html',
setup(build) {
build.onResolve({ filter: /\.html$/ }, args => ({
path: path.resolve(args.resolveDir, args.path),
namespace: 'html',
}));
build.onLoad({ filter: /.html/, namespace: 'html' }, (args) => {
let htmlContent = fs.readFileSync(args.path).toString('utf-8');

// replace env vars
if (config.env) {
const envPrefix = config.envPrefix || 'REACT_APP_';
const envVars = Object.entries(process.env || {}).filter(([name]) => name.startsWith(envPrefix));
htmlContent = envVars.reduce(
(memo, [name, value]) => memo.replace(new RegExp(`%${name}%`, 'igm'), value),
htmlContent,
);
}

return {
contents: htmlContent,
loader: 'file'
};
});

build.onEnd((result) => {
const outFiles = Object.keys((result.metafile || {}).outputs);
const jsFiles = outFiles.filter((p) => p.endsWith('.js'));
const cssFiles = outFiles.filter((p) => p.endsWith('.css'));
const htmlFiles = outFiles.filter((p) => p.endsWith('.html'));

const headerAppends = cssFiles.reduce(
(memo, p) => {
const filename = p.split(path.sep).slice(-1)[0];
return [...memo, `<link href="${filename}" rel="stylesheet">`];
},
[],
);

const bodyAppends = jsFiles.reduce(
(memo, p) => {
const filename = p.split(path.sep).slice(-1)[0];
return [...memo, `<script src="${filename}"></script>`];
},
[],
);

for (const htmlFile of htmlFiles) {
let htmlContent = fs.readFileSync(htmlFile).toString('utf-8');

// replace env vars
if (config.env) {
const envPrefix = config.envPrefix || 'REACT_APP_';
const envVars = Object.entries(process.env).filter(([name]) => name.startsWith(envPrefix));

htmlContent = envVars.reduce(
(memo, [name, value]) => memo.replace(new RegExp(`%${name}%`, 'igm'), value),
htmlContent,
);
}

// inject references to js and css files
htmlContent = htmlContent
.replace('</head>', [...headerAppends, '</head>'].join("\n"))
.replace('</body>', [...bodyAppends, '</body>'].join("\n"));

fs.writeFileSync(config.filename.replace('-[^.]+', ''), htmlContent);
}
});
},
});

module.exports = HtmlPlugin;
1 change: 1 addition & 0 deletions aws-proxy/aws_proxy/frontend/.yarnrc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
nodeLinker: node-modules
45 changes: 45 additions & 0 deletions aws-proxy/aws_proxy/frontend/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
{
"name": "aws_proxy",
"version": "0.1.0",
"private": true,
"license": "UNLICENSED",
"dependencies": {
"@emotion/react": "^11.11.4",
"@emotion/styled": "^11.11.5",
"@localstack/integrations": "1.2.2",
"@mui/material": "^5.15.20",
"axios": "^1.8.4",
"react": "^17.0.2",
"react-dom": "^17.0.2",
"react-router-dom": "^6.24.0",
"react-scripts": "5.0.1",
"typescript": "^4.9.5"
},
"devDependencies": {
"@esbuild-plugins/node-modules-polyfill": "^0.1.4",
"@testing-library/react": "^13.4.0",
"@types/node": "^16.18.99",
"@types/react": "^19.1.6",
"@types/react-dom": "^17.0.11",
"concurrently": "^8.2.2",
"esbuild": "^0.16.6",
"esbuild-envfile-plugin": "^1.0.2",
"esbuild-plugin-clean": "^1.0.1",
"esbuild-plugin-copy": "^0.3.0",
"esbuild-plugin-svgr": "^1.0.0",
"live-server": "^1.2.2"
},
"scripts": {
"start": "concurrently --restart-tries -1 --raw \"yarn serve\" \"yarn watch\"",
"serve": "live-server --port=3000 --host=0.0.0.0 --no-browser --watch=aws_proxy/server/static/index.html --entry-file=index.html ../server/static",
"watch": "node .esbuild --watch",
"build": "node .esbuild"
},
"resolutions": {
"react": "^17.0.2",
"react-dom": "^17.0.2",
"@types/react-dom": "^17.0.11",
"@mui/material": "^5.15.20"
},
"packageManager": "yarn@3.2.3"
}
Binary file added aws-proxy/aws_proxy/frontend/public/favicon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
15 changes: 15 additions & 0 deletions aws-proxy/aws_proxy/frontend/public/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
{
"short_name": "Proxy",
"name": "Aws Proxy",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
3 changes: 3 additions & 0 deletions aws-proxy/aws_proxy/frontend/public/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
Loading