diff --git a/.babelrc b/.babelrc new file mode 100644 index 00000000..313497cf --- /dev/null +++ b/.babelrc @@ -0,0 +1,12 @@ +{ + "presets": [ + ["env", { + "targets": { + "browsers": ["Chrome >= 65"] + }, + "debug": false, + "modules": false, + "useBuiltIns": "usage" + }] + ] +} diff --git a/.gitignore b/.gitignore index ba4d9556..6baa0959 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,11 @@ .DS_Store .idea ._* -manager/node_modules -manager/core* -manager/dist -manager/webpack_stats.html -config/* -letsencrypt/* +node_modules +core* +dist +webpack_stats.html +data/* +yarn-error.log +yarn.lock + diff --git a/bin/build b/bin/build new file mode 100755 index 00000000..43d749a6 --- /dev/null +++ b/bin/build @@ -0,0 +1,4 @@ +#!/bin/bash + +sudo /usr/local/bin/docker-compose run --no-deps --rm app npm run-script build +exit $? diff --git a/bin/npm b/bin/npm index 7a477952..a0863df0 100755 --- a/bin/npm +++ b/bin/npm @@ -1,20 +1,4 @@ #!/bin/bash -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -if hash realpath 2>/dev/null; then - export CODEBASE=$(realpath $SCRIPT_DIR/..) -elif hash grealpath 2>/dev/null; then - export CODEBASE=$(grealpath $SCRIPT_DIR/..) -else - export CODEBASE=$(readlink -e $SCRIPT_DIR/..) -fi - -if [ -z "$CODEBASE" ]; then - echo "Unable to determine absolute codebase directory" - exit 1 -fi - -cd "$CODEBASE" - -/usr/local/bin/docker-compose run --no-deps --rm -w /srv/manager app npm $@ +sudo /usr/local/bin/docker-compose run --no-deps --rm app npm $@ exit $? diff --git a/bin/yarn b/bin/yarn index fe3b1feb..e4fd807d 100755 --- a/bin/yarn +++ b/bin/yarn @@ -1,20 +1,4 @@ #!/bin/bash -SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" -if hash realpath 2>/dev/null; then - export CODEBASE=$(realpath $SCRIPT_DIR/..) -elif hash grealpath 2>/dev/null; then - export CODEBASE=$(grealpath $SCRIPT_DIR/..) -else - export CODEBASE=$(readlink -e $SCRIPT_DIR/..) -fi - -if [ -z "$CODEBASE" ]; then - echo "Unable to determine absolute codebase directory" - exit 1 -fi - -cd "$CODEBASE" - -/usr/local/bin/docker-compose run --no-deps --rm -w /srv/manager app yarn $@ +sudo /usr/local/bin/docker-compose run --no-deps --rm app yarn $@ exit $? diff --git a/docker-compose.yml b/docker-compose.yml index 96c125f7..dee8bb50 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,14 +1,31 @@ version: "2" services: app: - image: jc21/nginx-proxy-manager + image: jc21/node ports: - - 80:80 - - 81:81 - - 443:443 + - 8080:80 + - 8081:81 + - 8443:443 environment: - NODE_ENV=development + - FORCE_COLOR=1 volumes: - - ./config:/config - - ./letsencrypt:/etc/letsencrypt - - ./manager:/srv/manager + - ./data/letsencrypt:/etc/letsencrypt + - .:/srv/app + depends_on: + - db + links: + - db + command: node --max_old_space_size=250 --abort_on_uncaught_exception node_modules/nodemon/bin/nodemon.js + db: + image: mariadb:10.3.7 + environment: + MYSQL_ROOT_PASSWORD: "npm" + MYSQL_DATABASE: "npm" + MYSQL_USER: "npm" + MYSQL_PASSWORD: "npm" + volumes: + - ./config/my.cnf:/etc/mysql/conf.d/npm.cnf + - ./data/mysql:/var/lib/mysql + - ./data/initial-sql:/docker-entrypoint-initdb.d + diff --git a/knexfile.js b/knexfile.js new file mode 100644 index 00000000..3d735ea7 --- /dev/null +++ b/knexfile.js @@ -0,0 +1,19 @@ +module.exports = { + development: { + client: 'mysql', + migrations: { + tableName: 'migrations', + stub: 'src/backend/lib/migrate_template.js', + directory: 'src/backend/migrations' + } + }, + + production: { + client: 'mysql', + migrations: { + tableName: 'migrations', + stub: 'src/backend/lib/migrate_template.js', + directory: 'src/backend/migrations' + } + } +}; diff --git a/nodemon.json b/nodemon.json new file mode 100644 index 00000000..3c454d1e --- /dev/null +++ b/nodemon.json @@ -0,0 +1,5 @@ +{ + "verbose": false, + "ignore": ["dist", "data", "src/frontend"], + "ext": "js json ejs" +} diff --git a/package.json b/package.json new file mode 100644 index 00000000..ab3c3f52 --- /dev/null +++ b/package.json @@ -0,0 +1,68 @@ +{ + "name": "nginx-proxy-manager", + "version": "2.0.0", + "description": "A nice web interface for managing your endpoints", + "main": "src/backend/index.js", + "devDependencies": { + "babel-core": "^6.26.3", + "babel-loader": "^7.1.4", + "babel-minify-webpack-plugin": "^0.3.1", + "babel-preset-env": "^1.7.0", + "backbone": "^1.3.3", + "backbone.marionette": "^3.5.1", + "copy-webpack-plugin": "^4.5.1", + "css-loader": "^0.28.11", + "ejs-loader": "^0.3.1", + "file-loader": "^1.1.11", + "imports-loader": "^0.8.0", + "jquery": "^3.3.1", + "jquery-serializejson": "^2.8.1", + "mini-css-extract-plugin": "^0.4.0", + "moment": "^2.22.2", + "node-sass": "^4.9.0", + "nodemon": "^1.17.5", + "numeral": "^2.0.6", + "sass-loader": "^7.0.3", + "style-loader": "^0.21.0", + "tabler-ui": "git+https://github.com/tabler/tabler.git", + "underscore": "^1.8.3", + "webpack": "^4.12.0", + "webpack-cli": "^3.0.8", + "webpack-visualizer-plugin": "^0.1.11" + }, + "dependencies": { + "ajv": "^6.5.1", + "batchflow": "^0.4.0", + "bcrypt-then": "^1.1.0", + "body-parser": "^1.18.3", + "compression": "^1.7.2", + "config": "^1.30.0", + "ejs": "^2.6.1", + "express": "^4.16.3", + "gravatar": "^1.6.0", + "html-entities": "^1.2.1", + "json-schema-ref-parser": "^5.0.3", + "jsonwebtoken": "^8.3.0", + "knex": "^0.14.6", + "lodash": "^4.17.10", + "mysql": "^2.15.0", + "node-rsa": "^1.0.0", + "objection": "^1.1.10", + "path": "^0.12.7", + "restler": "^3.4.0", + "signale": "^1.2.1", + "unix-timestamp": "^0.2.0" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "dev": "webpack --mode development", + "build": "webpack --mode production", + "watch": "webpack-dev-server --mode development" + }, + "signale": { + "displayDate": true, + "displayTimestamp": true + }, + "author": "Jamie Curnow ", + "license": "MIT" +} diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 00000000..27325547 --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,134 @@ +const path = require('path'); +const webpack = require('webpack'); +const MiniCssExtractPlugin = require('mini-css-extract-plugin'); +const Visualizer = require('webpack-visualizer-plugin'); +const CopyWebpackPlugin = require('copy-webpack-plugin'); + +module.exports = { + entry: { + main: './src/frontend/js/index.js', + login: './src/frontend/js/login.js' + }, + output: { + path: path.resolve(__dirname, 'dist'), + filename: 'js/[name].js', + publicPath: '/' + }, + resolve: { + alias: { + 'tabler-core': 'tabler-ui/dist/assets/js/core', + 'bootstrap': 'tabler-ui/dist/assets/js/vendors/bootstrap.bundle.min', + 'sparkline': 'tabler-ui/dist/assets/js/vendors/jquery.sparkline.min', + 'selectize': 'tabler-ui/dist/assets/js/vendors/selectize.min', + 'tablesorter': 'tabler-ui/dist/assets/js/vendors/jquery.tablesorter.min', + 'vector-map': 'tabler-ui/dist/assets/js/vendors/jquery-jvectormap-2.0.3.min', + 'vector-map-de': 'tabler-ui/dist/assets/js/vendors/jquery-jvectormap-de-merc', + 'vector-map-world': 'tabler-ui/dist/assets/js/vendors/jquery-jvectormap-world-mill', + 'circle-progress': 'tabler-ui/dist/assets/js/vendors/circle-progress.min' + } + }, + module: { + rules: [ + // Shims for tabler-ui + { + test: /assets\/js\/core/, + loader: 'imports-loader?bootstrap' + }, + { + test: /jquery-jvectormap-de-merc/, + loader: 'imports-loader?vector-map' + }, + { + test: /jquery-jvectormap-world-mill/, + loader: 'imports-loader?vector-map' + }, + + // other: + { + test: /\.js$/, + exclude: /node_modules/, + use: { + loader: 'babel-loader' + } + }, + { + test: /\.ejs$/, + loader: 'ejs-loader' + }, + { + test: /\.scss$/, + use: [ + MiniCssExtractPlugin.loader, + 'css-loader', + 'sass-loader' + ] + }, + { + test: /.*tabler.*\.(jpe?g|gif|png|svg|eot|woff|ttf)$/, + use: [ + { + loader: 'file-loader', + options: { + outputPath: 'assets/tabler-ui/' + } + } + ] + } + ] + }, + plugins: [ + new webpack.ProvidePlugin({ + $: 'jquery', + jQuery: 'jquery', + _: 'underscore' + }), + new MiniCssExtractPlugin({ + filename: 'css/[name].css', + chunkFilename: 'css/[id].css' + }), + new Visualizer({ + filename: '../webpack_stats.html' + }), + new CopyWebpackPlugin([{ + from: 'src/frontend/app-images', + to: 'images', + toType: 'dir', + context: '/srv/app' + }]), + new webpack.optimize.LimitChunkCountPlugin({ + maxChunks: 1, // Must be greater than or equal to one + minChunkSize: 999999999 + }) + ], + /* + optimization: { + splitChunks: { + chunks (chunk) { + // exclude `my-excluded-chunk` + return false; + }, + minSize: 999999999, + minChunks: 1, + name: true, + cacheGroups: { + vendors: { + test: /[\\/]node_modules[\\/]/, + priority: -10 + }, + default: { + minChunks: 2, + priority: -20, + reuseExistingChunk: true + } + } + } + }, + */ + devServer: { + contentBase: path.join(__dirname, 'dist'), + compress: true, + port: 8080, + disableHostCheck: true, + host: '0.0.0.0' + } +};