Jelajahi Sumber

Merge pull request #1067 from porter-dev/0.8.0-no-docker-dev-env

[0.8.0] Environment without docker & webpack optimizations
abelanger5 4 tahun lalu
induk
melakukan
9dd29eb7ec

+ 3 - 3
.air.toml

@@ -7,11 +7,11 @@ tmp_dir = "tmp"
 
 [build]
 # Just plain old shell command. You could use `make` as well.
-cmd = "go build -o ./tmp/ready ./cmd/ready; go build -o ./tmp/migrate ./cmd/migrate; go build -o ./tmp/app ./cmd/app"
+cmd = "go build -o ./tmp/app ./cmd/app"
 # Binary file yields from `cmd`.
-bin = "tmp/migrate; tmp/app"
+bin = "tmp/app"
 # Customize binary.
-full_bin = "tmp/migrate; tmp/app"
+full_bin = "tmp/app"
 # Watch these filename extensions.
 include_ext = ["go", "mod", "sum", "html"]
 # Ignore these filename extensions or directories.

+ 3 - 0
.gitignore

@@ -13,6 +13,7 @@ gon*.hcl
 staging.sh
 *.crt
 *.key
+bin
 
 # Local .terraform directories
 **/.terraform/*
@@ -55,3 +56,5 @@ override.tf.json
 # Ignore CLI configuration files
 .terraformrc
 terraform.rc
+
+tmp

+ 14 - 0
Makefile

@@ -0,0 +1,14 @@
+BINDIR      := $(CURDIR)/bin
+VERSION ?= dev
+
+start-dev: install setup-env-files
+	bash ./scripts/dev-environment/StartDevServer.sh
+
+install: 
+	bash ./scripts/dev-environment/SetupEnvironment.sh
+
+setup-env-files: 
+	bash ./scripts/dev-environment/CreateDefaultEnvFiles.sh
+
+build-cli: 
+	go build -ldflags="-w -s -X 'github.com/porter-dev/porter/cli/cmd.Version=${VERSION}'" -a -tags cli -o $(BINDIR)/porter ./cli

+ 4 - 0
dashboard/babel.config.json

@@ -0,0 +1,4 @@
+{
+  "plugins": ["lodash"],
+  "presets": ["@babel/preset-env", "@babel/preset-react", "@babel/preset-typescript"]
+}

File diff ditekan karena terlalu besar
+ 2360 - 45
dashboard/package-lock.json


+ 25 - 12
dashboard/package.json

@@ -4,14 +4,6 @@
   "private": true,
   "dependencies": {
     "@material-ui/core": "^4.11.3",
-    "@types/d3-array": "^2.9.0",
-    "@types/d3-time-format": "^3.0.0",
-    "@types/js-yaml": "^4.0.1",
-    "@types/lodash": "^4.14.165",
-    "@types/markdown-to-jsx": "^6.11.3",
-    "@types/material-ui": "^0.21.8",
-    "@types/qs": "^6.9.5",
-    "@types/random-words": "^1.1.0",
     "@visx/axis": "^1.6.1",
     "@visx/curve": "^1.0.0",
     "@visx/event": "^1.3.0",
@@ -27,6 +19,7 @@
     "axios": "^0.20.0",
     "brace": "^0.11.1",
     "clipboard": "^2.0.8",
+    "core-js": "^3.16.1",
     "d3-array": "^2.11.0",
     "d3-time-format": "^3.0.0",
     "dotenv": "^8.2.0",
@@ -41,24 +34,37 @@
     "react": "^16.13.1",
     "react-ace": "^9.1.3",
     "react-dom": "^16.13.1",
+    "react-error-boundary": "^3.1.3",
     "react-modal": "^3.11.2",
     "react-router-dom": "^5.2.0",
     "react-table": "^7.7.0",
+    "regenerator-runtime": "^0.13.9",
     "semver": "^7.3.5",
-    "styled-components": "^5.2.0",
-    "react-error-boundary": "^3.1.3"
+    "styled-components": "^5.2.0"
   },
   "scripts": {
     "test": "echo \"Error: no test specified\" && exit 1",
-    "start": "webpack-dev-server --host 0.0.0.0 --hot --inline --port 8080",
-    "build": "webpack"
+    "start": "webpack-dev-server",
+    "build": "NODE_ENV=\"production\" webpack",
+    "build-and-analyze": "ENABLE_ANALYZER=true NODE_ENV=\"production\" webpack"
   },
   "devDependencies": {
+    "@babel/core": "^7.15.0",
+    "@babel/preset-env": "^7.15.0",
+    "@babel/preset-react": "^7.14.5",
+    "@babel/preset-typescript": "^7.15.0",
+    "@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
     "@testing-library/jest-dom": "^4.2.4",
     "@testing-library/react": "^9.3.2",
     "@testing-library/user-event": "^7.1.2",
+    "@types/d3-array": "^2.9.0",
+    "@types/d3-time-format": "^3.0.0",
     "@types/jest": "^24.0.0",
     "@types/js-base64": "^3.0.0",
+    "@types/js-yaml": "^4.0.1",
+    "@types/lodash": "^4.14.165",
+    "@types/markdown-to-jsx": "^6.11.3",
+    "@types/material-ui": "^0.21.8",
     "@types/node": "^12.12.62",
     "@types/qs": "^6.9.5",
     "@types/random-words": "^1.1.0",
@@ -70,14 +76,21 @@
     "@types/react-table": "^7.7.1",
     "@types/semver": "^7.3.5",
     "@types/styled-components": "^5.1.3",
+    "@types/terser-webpack-plugin": "^4.2.2",
+    "@types/webpack-dev-server": "^3.11.5",
+    "babel-loader": "^8.2.2",
+    "babel-plugin-lodash": "^3.3.4",
     "file-loader": "^6.1.0",
     "html-webpack-plugin": "^4.5.0",
     "prettier": "2.2.1",
     "qs": "^6.9.4",
+    "react-refresh": "^0.10.0",
     "source-map-loader": "^1.1.0",
+    "terser-webpack-plugin": "^4.2.3",
     "ts-loader": "^8.0.4",
     "typescript": "^4.1.2",
     "webpack": "^4.44.2",
+    "webpack-bundle-analyzer": "^4.4.2",
     "webpack-cli": "^3.3.12",
     "webpack-dev-server": "^3.11.0"
   }

+ 3 - 0
dashboard/src/index.tsx

@@ -1,3 +1,6 @@
+import "core-js/stable";
+import "regenerator-runtime/runtime";
+
 import * as React from "react";
 import * as ReactDOM from "react-dom";
 import App from "./App";

+ 94 - 7
dashboard/webpack.config.js

@@ -1,24 +1,48 @@
 const path = require("path");
 const HtmlWebpackPlugin = require("html-webpack-plugin");
 const webpack = require("webpack");
+const ReactRefreshWebpackPlugin = require("@pmmmwh/react-refresh-webpack-plugin");
+
 const dotenv = require("dotenv");
 
+const BundleAnalyzerPlugin = require("webpack-bundle-analyzer")
+  .BundleAnalyzerPlugin;
+
+const TerserPlugin = require("terser-webpack-plugin");
+
 module.exports = () => {
   const env = dotenv.config().parsed;
   const envKeys = Object.keys(env).reduce((prev, next) => {
     prev[`process.env.${next}`] = JSON.stringify(env[next]);
     return prev;
   }, {});
-
-  return {
-    entry: "./src/index.tsx",
+  // Check first the env file and if it's empty, check out the node env of the process.
+  let isDevelopment = env.NODE_ENV !== "production";
+  if (process.env.NODE_ENV !== env.NODE_ENV) {
+    isDevelopment = process.env.NODE_ENV !== "production";
+  }
+  /**
+   * @type {webpack.Configuration}
+   */
+  const config = {
+    entry: ["./src/index.tsx"],
     target: "web",
-    mode: "development",
+    mode: isDevelopment ? "development" : "production",
     module: {
       rules: [
         {
-          test: /\.(ts|tsx)$/,
-          loader: "ts-loader",
+          test: /\.(ts|tsx|mjs|js|jsx)$/,
+          exclude: /node_modules/,
+          use: [
+            {
+              loader: require.resolve("babel-loader"),
+              options: {
+                plugins: [
+                  isDevelopment && require.resolve("react-refresh/babel"),
+                ].filter(Boolean),
+              },
+            },
+          ],
         },
         {
           enforce: "pre",
@@ -56,6 +80,9 @@ module.exports = () => {
     devServer: {
       historyApiFallback: true,
       disableHostCheck: true,
+      host: "0.0.0.0",
+      port: env.DEV_SERVER_PORT || 8080,
+      hot: true,
     },
     plugins: [
       new HtmlWebpackPlugin({
@@ -63,6 +90,66 @@ module.exports = () => {
         segmentKey: `${process.env.SEGMENT_PUBLIC_KEY}`,
       }),
       new webpack.DefinePlugin(envKeys),
-    ],
+      isDevelopment && new ReactRefreshWebpackPlugin(),
+    ].filter(Boolean),
   };
+
+  if (!isDevelopment) {
+    config.optimization = {
+      minimize: true,
+      minimizer: [
+        new TerserPlugin({
+          test: /\.(ts|tsx|mjs|js|jsx)$/,
+          terserOptions: {
+            parse: {
+              // We want terser to parse ecma 8 code. However, we don't want it
+              // to apply minification steps that turns valid ecma 5 code
+              // into invalid ecma 5 code. This is why the `compress` and `output`
+              ecma: 8,
+            },
+            compress: {
+              ecma: 5,
+              warnings: false,
+              inline: 2,
+            },
+            mangle: {
+              // Find work around for Safari 10+
+              safari10: true,
+            },
+            output: {
+              ecma: 5,
+              comments: false,
+              ascii_only: true,
+            },
+          },
+
+          // Use multi-process parallel running to improve the build speed
+          parallel: true,
+        }),
+      ],
+    };
+  }
+
+  if (env.ENABLE_ANALYZER) {
+    config.plugins.push(new BundleAnalyzerPlugin());
+  }
+  console.log(env);
+  if (env.ENABLE_PROXY) {
+    console.log("WORKED!");
+    if (!env.API_SERVER) {
+      throw new Error(
+        "API_SERVER is not present on .env! Please setup the api server url if you want the proxy to work! API_SERVER example: http://localhost:8080"
+      );
+    }
+    config.devServer.proxy = {
+      "/api": {
+        logLevel: "debug",
+        target: env.API_SERVER, // target host
+        changeOrigin: true, // needed for virtual hosted sites
+        ws: true, // proxy websockets
+      },
+    };
+  }
+
+  return config;
 };

+ 26 - 6
docs/developing/setup.md

@@ -22,9 +22,27 @@ DB_NAME=porter
 SQL_LITE=false
 ```
 
-Once you've done this, go to the root repository, and run `docker-compose -f docker-compose.dev.yaml up`. You should see postgres, webpack, and porter containers spin up. When the webpack and porter containers have finished compiling and have spun up successfully (this will take 5-10 minutes after the containers start), you can navigate to `localhost:8080` and you should be greeted with the "Log In" screen. Create a user by entering an email/password on the "Register" screen. 
+Once you've done this, go to the root repository, and run `docker-compose -f docker-compose.dev.yaml up`. You should see postgres, webpack, and porter containers spin up. When the webpack and porter containers have finished compiling and have spun up successfully (this will take 5-10 minutes after the containers start), you can navigate to `localhost:8080` and you should be greeted with the "Log In" screen. Create a user by entering an email/password on the "Register" screen.
 
-At this point, you can make a change to any `.go` file to trigger a backend rebuild, and any file in `/dashboard/src` to trigger a hot reload. 
+At this point, you can make a change to any `.go` file to trigger a backend rebuild, and any file in `/dashboard/src` to trigger a hot reload.
+
+## Setup without docker
+
+While docker is an awesome way of getting started as it simulates the real environment that we use on our hosted dashboard, for some people this may bee too much.
+
+In order to decrease the complexity of all the environment, you can just run the development environment locally without docker.
+
+After cloning the repo you should only execute `make start-dev` this will ask you to install the dependencies and also run the server and the frontend in a single console.
+It will also create some env files with default values that will simplify the process!
+
+### Disclaimer
+
+For the command `make start-dev` to work, you should be working under a bash environment (WSL on windows, Linux or MacOS), also you will need go, node and npm installed
+for it to work.
+
+### Disclaimer
+
+This environment is experimental, if you run into any issue don't doubt in contact us through our [discord!](https://discord.gg/GJynMR3KXK)
 
 ## Getting PostgreSQL Access
 
@@ -34,7 +52,7 @@ You can get `psql` access by running the following:
 
 This will prompt you for a password. Enter `porter`, and you should see the `psql` shell!
 
-### Setting your email to be verified 
+### Setting your email to be verified
 
 If you are getting blocked out of the dashboard because your email is not verified (fixed in `v0.6.2` of Porter, so make sure you've pulled from `master` recently), you can update your email in the database to `verified":
 
@@ -43,16 +61,18 @@ If you are getting blocked out of the dashboard because your email is not verifi
 ## Setting up Minikube
 
 These steps will help you get set up with a minikube cluster that can be used for development. Prerequisities:
+
 - `kubectl` installed locally
 - Development instance of Porter is running
 
 Following the OS-specific steps to get minikube running:
+
 - [MacOS](#macos)
 - [Linux](#linux)
 
 If you now navigate to `http://localhost:8080`, you should see the minikube cluster attached! There will be some limitations:
-- **It is not possible to expose a service that you create. Whenever you create a web service, de-select the "Expose to external traffic" option.**
 
+- **It is not possible to expose a service that you create. Whenever you create a web service, de-select the "Expose to external traffic" option.**
 
 ### MacOS
 
@@ -119,6 +139,6 @@ If using Chrome, paste the following into the Chrome address bar:
 
 > chrome://flags/#allow-insecure-localhost
 
-And then Enable the **Allow invalid certificates for resources loaded from localhost** field. 
+And then Enable the **Allow invalid certificates for resources loaded from localhost** field.
 
-Finally, run `docker-compose -f docker-compose.dev-secure.yaml up` instead of the standard docker-compose file. 
+Finally, run `docker-compose -f docker-compose.dev-secure.yaml up` instead of the standard docker-compose file.

+ 56 - 0
scripts/dev-environment/CreateDefaultEnvFiles.sh

@@ -0,0 +1,56 @@
+#!/bin/bash
+
+create-backend-env-file() {
+  FILE=./docker/.env
+cat > $FILE <<- EOM
+SERVER_URL=http://localhost:8080
+SERVER_PORT=8080 # Be sure that doesn't colision with the frontend port
+SQL_LITE=true
+SQL_LITE_PATH=./porter.db
+
+# Disable redis by default on non docker environment, if you want to setup redis you can complete the variables commented down below
+REDIS_ENABLED=false
+# REDIS_HOST=redis
+# REDIS_PORT=6379
+# REDIS_USER=foo
+# REDIS_PASS=bar
+# REDIS_DB=0
+
+# If you don't wanna use SQL lite you should fill this data with the postgres connection details
+# DB_HOST=localhost 
+# DB_PORT=5400
+# DB_USER=porter
+# DB_PASS=porter
+# DB_NAME=porter
+
+EOM
+}
+
+create-frontend-env-file() {
+  FILE=./dashboard/.env
+cat > $FILE <<- EOM
+NODE_ENV=development
+
+# Tell the webpack dev server in wich port we wanna run, it defaults to 8080 but we have to be carefull this is not the same port as the backend
+DEV_SERVER_PORT=8081
+
+# Usually we would use nginx, but for this environment we're going to enable webpack-dev-server proxy 
+ENABLE_PROXY=true 
+
+# API server url, this url will be used for the proxy to redirect all /api calls
+API_SERVER=http://localhost:8080 
+EOM
+}
+
+if [[ ! -e ./dashboard/.env ]]
+then
+  echo "Dashboard env file (./dashboard/.env) not found, creating one with defaults"
+  create-frontend-env-file
+fi
+
+if [[ ! -e ./docker/.env ]]
+then
+  echo "Server env file (./docker/.env) not found, creating one with defaults"
+  create-backend-env-file
+fi
+

+ 38 - 0
scripts/dev-environment/SetupEnvironment.sh

@@ -0,0 +1,38 @@
+#!/bin/bash
+
+# Setup all the environment requirements.
+
+REQUIRED_APPLICATIONS=('node' 'go' 'npm')
+for i in "${REQUIRED_APPLICATIONS[@]}"; do
+  if ! command -v $i &> /dev/null
+  then
+    echo "${i} could not be found, please install to be able to execute dev environment"
+    exit
+  fi
+done
+
+
+if ! command -v air &> /dev/null
+then 
+  printf "\n"
+  read -p "cosmtrek/air is required to continue, do you want to install it? y/N: " -n 1 -r
+  if [[ $REPLY =~ ^[Yy]$ ]]
+  then
+    echo "Yes"
+    curl -sSfL https://raw.githubusercontent.com/cosmtrek/air/master/install.sh | sh -s -- -b $(go env GOPATH)/bin
+    printf "\nInstalled Air\n"
+    air -v
+  else 
+    printf "\nCanceled script, exiting program\n"
+    exit
+  fi
+fi
+
+
+if [[ ! -d ./dashboard/node_modules ]]; then 
+  echo "Couldn't find node_modules, installing npm packages"
+  cd ./dashboard && npm install;
+  cd ../;  
+else
+  echo "Node modules found! Proceeding to start server"
+fi

+ 33 - 0
scripts/dev-environment/StartDevServer.sh

@@ -0,0 +1,33 @@
+#!/bin/bash
+
+printf "\033c"
+
+startFrontend() {
+  cd ./dashboard && npm start;
+}
+
+startBackend() {
+  # Load env variables for backend
+  if [[ -e ./docker/.env ]]
+  then
+    set -a # automatically export all variables
+    source ./docker/.env
+    set +a
+  else 
+    echo "Couldn't find any backend env variables, exiting process"
+    exit
+  fi
+  air -c .air.toml
+}
+
+startBackend &
+startFrontend &
+wait
+
+cleanup() {
+    rv=$?
+    clear
+    exit $rv
+}
+
+trap "cleanup" EXIT

Beberapa file tidak ditampilkan karena terlalu banyak file yang berubah dalam diff ini