initial commit
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
dist
|
||||
node_modules
|
||||
.env
|
||||
.env.*
|
||||
@@ -0,0 +1 @@
|
||||
BASE_URL=https://portal.mydomain.com
|
||||
@@ -0,0 +1 @@
|
||||
**/*.js
|
||||
@@ -0,0 +1,4 @@
|
||||
.env
|
||||
dist
|
||||
node_modules
|
||||
yarn-error.log
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
# syntax=docker/dockerfile:1
|
||||
|
||||
FROM node:18-alpine AS builder
|
||||
|
||||
WORKDIR /app
|
||||
COPY . .
|
||||
RUN npm install
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
||||
RUN npm run build
|
||||
|
||||
FROM node:18-alpine
|
||||
|
||||
ENV NODE_ENV=production
|
||||
|
||||
WORKDIR /app
|
||||
COPY package.json .
|
||||
COPY package-lock.json .
|
||||
RUN npm install
|
||||
COPY --from=builder /app/dist .
|
||||
|
||||
CMD ["node", "./server/server.js"]
|
||||
Generated
+15981
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,70 @@
|
||||
{
|
||||
"name": "vpn-portal",
|
||||
"version": "1.0.0",
|
||||
"description": "Portal for openvpn auth and profiles",
|
||||
"scripts": {
|
||||
"build": "run-s build:server build:web",
|
||||
"build:server": "webpack --config webpack.server.production.js",
|
||||
"build:web": "webpack --config webpack.web.production.js",
|
||||
"build:server:once": "webpack --config webpack.server.development.js",
|
||||
"dev:server": "npm run build:server:once && run-p nodemon:prod watch:server",
|
||||
"watch:server": "webpack --config webpack.server.development.js --watch",
|
||||
"nodemon:prod": "nodemon dist/server/server.js"
|
||||
},
|
||||
"author": "",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"@webcomponents/webcomponentsjs": "^2.7.0",
|
||||
"express": "^4.18.2",
|
||||
"haunted": "^5.0.0",
|
||||
"lit-html": "^2.6.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/webpack-dev-middleware": "^5.3.0",
|
||||
"@types/webpack-hot-middleware": "^2.25.6",
|
||||
"@typescript-eslint/eslint-plugin": "^5.51.0",
|
||||
"@typescript-eslint/parser": "^5.51.0",
|
||||
"clean-webpack-plugin": "^4.0.0",
|
||||
"copy-webpack-plugin": "^11.0.0",
|
||||
"css-loader": "^6.7.3",
|
||||
"dotenv-webpack": "^8.0.1",
|
||||
"eslint": "^8.33.0",
|
||||
"extract-loader": "^5.1.0",
|
||||
"html-webpack-plugin": "^5.5.0",
|
||||
"node-sass": "^8.0.0",
|
||||
"nodemon": "^2.0.20",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"sass-loader": "^13.2.0",
|
||||
"ts-loader": "^9.4.2",
|
||||
"typescript": "^4.9.5",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^5.0.1",
|
||||
"webpack-dev-middleware": "^6.0.1",
|
||||
"webpack-hot-middleware": "^2.25.3",
|
||||
"webpack-merge": "^5.8.0",
|
||||
"webpack-node-externals": "^3.0.0"
|
||||
},
|
||||
"nodemonConfig": {
|
||||
"exec": "node -r dotenv/config",
|
||||
"watch": [
|
||||
"dist/server"
|
||||
]
|
||||
},
|
||||
"eslintConfig": {
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"extends": [
|
||||
"eslint:recommended",
|
||||
"plugin:@typescript-eslint/eslint-recommended",
|
||||
"plugin:@typescript-eslint/recommended"
|
||||
],
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018,
|
||||
"sourceType": "module"
|
||||
},
|
||||
"rules": {
|
||||
"@typescript-eslint/no-explicit-any": 0,
|
||||
"@typescript-eslint/explicit-function-return-type": 0
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||
<script src="webcomponents-loader.js"></script>
|
||||
</head>
|
||||
<body></body>
|
||||
</html>
|
||||
@@ -0,0 +1,5 @@
|
||||
import express from "express";
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
export default router;
|
||||
@@ -0,0 +1,18 @@
|
||||
import express from "express";
|
||||
import router from "./router";
|
||||
import webpack from "webpack";
|
||||
import webpackDevMiddleware from "webpack-dev-middleware";
|
||||
import webpackHotMiddleware from "webpack-hot-middleware";
|
||||
import webpackConfig from "../../webpack.web.development.js";
|
||||
|
||||
const app = express();
|
||||
|
||||
const compiler = webpack(webpackConfig);
|
||||
|
||||
app.use(webpackDevMiddleware(compiler));
|
||||
app.use(webpackHotMiddleware(compiler));
|
||||
app.use(router);
|
||||
|
||||
app.listen(8080, () => {
|
||||
console.log("Server started");
|
||||
});
|
||||
@@ -0,0 +1,16 @@
|
||||
import express from "express";
|
||||
import router from "./router";
|
||||
import path from "path";
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use(express.static(path.join(__dirname, "..", "web")));
|
||||
app.use(router);
|
||||
|
||||
const server = app.listen(8080, () => {
|
||||
console.log("Server started");
|
||||
});
|
||||
|
||||
process.on("SIGTERM", () => {
|
||||
server.close();
|
||||
});
|
||||
@@ -0,0 +1,97 @@
|
||||
import { unsafeCSS, supportsAdoptingStyleSheets, CSSResult } from "lit-element";
|
||||
import { useState, useEffect, useLayoutEffect, useMemo, useRef } from "haunted";
|
||||
|
||||
export function useStylesheet(initialStyles: CSSResult[] | CSSResult) {
|
||||
const [needsShim, setNeedsShim] = useState(false);
|
||||
const userStyles = useRef(initialStyles);
|
||||
|
||||
const styles = useMemo(() => {
|
||||
let _styles: CSSResult[];
|
||||
|
||||
if (Array.isArray(userStyles.current)) {
|
||||
// De-duplicate styles preserving the _last_ instance in the set.
|
||||
// This is a performance optimization to avoid duplicated styles that can
|
||||
// occur especially when composing via subclassing.
|
||||
// The last item is kept to try to preserve the cascade order with the
|
||||
// assumption that it's most important that last added styles override
|
||||
// previous styles.
|
||||
const addStyles = (styles: CSSResult[], set: Set<CSSResult>) =>
|
||||
styles.reduceRight(
|
||||
(set, s) =>
|
||||
// Note: On IE set.add() does not return the set
|
||||
Array.isArray(s) ? addStyles(s, set) : (set.add(s), set),
|
||||
set
|
||||
);
|
||||
// Array.from does not work on Set in IE, otherwise return
|
||||
// Array.from(addStyles(userStyles, new Set<CSSResult>())).reverse()
|
||||
const set = addStyles(userStyles.current, new Set<CSSResult>());
|
||||
const styles: CSSResult[] = [];
|
||||
set.forEach((v) => styles.unshift(v));
|
||||
_styles = styles;
|
||||
} else {
|
||||
_styles = userStyles.current === undefined ? [] : [userStyles.current];
|
||||
}
|
||||
|
||||
// Ensure that there are no invalid CSSStyleSheet instances here. They are
|
||||
// invalid in two conditions.
|
||||
// (1) the sheet is non-constructible (`sheet` of a HTMLStyleElement), but
|
||||
// this is impossible to check except via .replaceSync or use
|
||||
// (2) the ShadyCSS polyfill is enabled (:. supportsAdoptingStyleSheets is
|
||||
// false)
|
||||
return _styles.map((s) => {
|
||||
if (s instanceof CSSStyleSheet && !supportsAdoptingStyleSheets) {
|
||||
// Flatten the cssText from the passed constructible stylesheet (or
|
||||
// undetectable non-constructible stylesheet). The user might have
|
||||
// expected to update their stylesheets over time, but the alternative
|
||||
// is a crash.
|
||||
const cssText: string = Array.prototype.slice
|
||||
.call(s.cssRules)
|
||||
.reduce((css: string, rule: CSSRule) => css + rule.cssText, "");
|
||||
return unsafeCSS(cssText);
|
||||
}
|
||||
return s;
|
||||
});
|
||||
}, [userStyles.current]);
|
||||
|
||||
useLayoutEffect(
|
||||
function () {
|
||||
const elm = this.host as Element;
|
||||
// There are three separate cases here based on Shadow DOM support.
|
||||
// (1) shadowRoot polyfilled: use ShadyCSS
|
||||
// (2) shadowRoot.adoptedStyleSheets available: use it
|
||||
// (3) shadowRoot.adoptedStyleSheets polyfilled: append styles after
|
||||
// rendering
|
||||
if (
|
||||
window["ShadyCSS"] !== undefined &&
|
||||
!window["ShadyCSS"].nativeShadow
|
||||
) {
|
||||
window["ShadyCSS"].ScopingShim.prepareAdoptedCssText(
|
||||
styles.map((s) => (s instanceof CSSResult ? s.cssText : "")),
|
||||
elm.localName
|
||||
);
|
||||
} else if (supportsAdoptingStyleSheets) {
|
||||
elm.shadowRoot!.adoptedStyleSheets = styles.map((s) =>
|
||||
s instanceof CSSStyleSheet ? s : s.styleSheet!
|
||||
);
|
||||
} else {
|
||||
setNeedsShim(true);
|
||||
}
|
||||
},
|
||||
[styles]
|
||||
);
|
||||
|
||||
useEffect(
|
||||
function () {
|
||||
const elm = this.host as Element;
|
||||
if (needsShim) {
|
||||
styles.forEach((s) => {
|
||||
const style = document.createElement("style");
|
||||
style.textContent = s.cssText;
|
||||
elm.shadowRoot!.appendChild(style);
|
||||
});
|
||||
setNeedsShim(false);
|
||||
}
|
||||
},
|
||||
[needsShim, styles]
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
:host {
|
||||
font-family: Ubuntu, sans-serif;
|
||||
display: block;
|
||||
border: solid 1px black;
|
||||
padding: 15px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
color: #77216f;
|
||||
}
|
||||
|
||||
button {
|
||||
border-radius: 4px;
|
||||
padding: 8px;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
border: 0;
|
||||
background-color: #aea79f;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
import { component, useState } from "haunted";
|
||||
import { html, render } from "lit-html";
|
||||
import { css, unsafeCSS } from "lit-element";
|
||||
import { useStylesheet } from "./hooks/css";
|
||||
import style from "./main.scss";
|
||||
|
||||
const CSS = css`
|
||||
${unsafeCSS(style)}
|
||||
`;
|
||||
|
||||
if (module["hot"]) {
|
||||
module["hot"].accept(() => {
|
||||
window.location.reload();
|
||||
});
|
||||
}
|
||||
|
||||
const AppComp = () => {
|
||||
useStylesheet(CSS);
|
||||
const [counter, setCounter] = useState(0);
|
||||
|
||||
return html`
|
||||
<h1>My App</h1>
|
||||
<p>Value = ${counter}</p>
|
||||
<button
|
||||
@click=${() => {
|
||||
setCounter(counter + 1);
|
||||
}}
|
||||
>
|
||||
increment
|
||||
</button>
|
||||
`;
|
||||
};
|
||||
|
||||
customElements.define("my-app", component(AppComp));
|
||||
|
||||
render(html`<my-app></my-app>`, document.body);
|
||||
Vendored
+20
@@ -0,0 +1,20 @@
|
||||
// typings.d.ts
|
||||
declare module '*.scss' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module '*.png' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module '*.jpg' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
|
||||
declare module '*.gif' {
|
||||
const content: string;
|
||||
export default content;
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"module": "commonjs",
|
||||
"removeComments": true,
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": ["src/server", "src/shared"]
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ESNext",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"removeComments": true,
|
||||
"esModuleInterop": true
|
||||
},
|
||||
"include": ["src/web", "src/shared"]
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
const path = require("path");
|
||||
|
||||
module.exports = {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
exclude: [/node_modules/],
|
||||
test: /\.ts$/,
|
||||
loader: "ts-loader",
|
||||
options: { configFile: "tsconfig.server.json" },
|
||||
},
|
||||
],
|
||||
},
|
||||
output: {
|
||||
filename: "server.js",
|
||||
path: path.resolve(__dirname, "dist", "server"),
|
||||
},
|
||||
resolve: {
|
||||
extensions: [".ts", ".js"],
|
||||
},
|
||||
target: "node",
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
|
||||
const { merge } = require("webpack-merge");
|
||||
const nodeExternals = require("webpack-node-externals");
|
||||
const path = require("path");
|
||||
const webpack = require("webpack");
|
||||
|
||||
const common = require("./webpack.server.common.js");
|
||||
|
||||
module.exports = merge(common, {
|
||||
devtool: "inline-source-map",
|
||||
entry: [path.join(__dirname, "src/server/server-dev.ts")],
|
||||
externals: [ nodeExternals(), ],
|
||||
mode: "development",
|
||||
plugins: [new CleanWebpackPlugin()],
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
|
||||
const { merge } = require("webpack-merge");
|
||||
const nodeExternals = require("webpack-node-externals");
|
||||
const path = require("path");
|
||||
|
||||
const common = require("./webpack.server.common.js");
|
||||
|
||||
module.exports = merge(common, {
|
||||
devtool: "source-map",
|
||||
node: { __dirname: false },
|
||||
entry: [path.join(__dirname, "src/server/server.ts")],
|
||||
externals: [nodeExternals()],
|
||||
mode: "production",
|
||||
plugins: [new CleanWebpackPlugin()],
|
||||
});
|
||||
@@ -0,0 +1,51 @@
|
||||
const path = require("path");
|
||||
const { CleanWebpackPlugin } = require("clean-webpack-plugin");
|
||||
const HtmlWebpackPlugin = require("html-webpack-plugin");
|
||||
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||
const Dotenv = require("dotenv-webpack");
|
||||
|
||||
module.exports = {
|
||||
target: "web",
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
exclude: [/node_modules/],
|
||||
test: /\.ts$/,
|
||||
loader: "ts-loader",
|
||||
options: { configFile: "tsconfig.web.json" },
|
||||
},
|
||||
{
|
||||
test: /\.(css|scss)$/,
|
||||
use: ["css-loader", "sass-loader"],
|
||||
},
|
||||
{
|
||||
test: /\.(png|jpg|gif)$/,
|
||||
type: "asset/resource",
|
||||
},
|
||||
],
|
||||
},
|
||||
output: {
|
||||
filename: "bundle.[name].js",
|
||||
path: path.resolve(__dirname, "dist", "web"),
|
||||
},
|
||||
resolve: {
|
||||
extensions: [".ts", ".js"],
|
||||
},
|
||||
plugins: [
|
||||
new CleanWebpackPlugin(),
|
||||
new HtmlWebpackPlugin({
|
||||
template: "./src/index.ejs",
|
||||
title: "My App",
|
||||
}),
|
||||
new CopyWebpackPlugin({
|
||||
patterns: [
|
||||
"./node_modules/@webcomponents/webcomponentsjs/webcomponents-loader.js",
|
||||
{
|
||||
from: "./node_modules/@webcomponents/webcomponentsjs/bundles",
|
||||
to: "bundles",
|
||||
},
|
||||
],
|
||||
}),
|
||||
new Dotenv(),
|
||||
],
|
||||
};
|
||||
@@ -0,0 +1,13 @@
|
||||
const { merge, } = require("webpack-merge");
|
||||
const webpack = require("webpack");
|
||||
|
||||
const common = require("./webpack.web.common.js");
|
||||
|
||||
module.exports = merge(common, {
|
||||
devtool: "inline-source-map",
|
||||
entry: ["webpack-hot-middleware/client?timeout=1000&reload=true", "./src/web/main.ts"],
|
||||
mode: "development",
|
||||
plugins: [
|
||||
new webpack.HotModuleReplacementPlugin(),
|
||||
],
|
||||
});
|
||||
@@ -0,0 +1,10 @@
|
||||
const { merge } = require("webpack-merge");
|
||||
const path = require("path");
|
||||
|
||||
const common = require("./webpack.web.common.js");
|
||||
|
||||
module.exports = merge(common, {
|
||||
// devtool: "source-map",
|
||||
entry: [path.join(__dirname, "src/web/main.ts")],
|
||||
mode: "production",
|
||||
});
|
||||
Reference in New Issue
Block a user