From 7ef7ee6d35112f8b343c5c0997dd5ed2eb9f1745 Mon Sep 17 00:00:00 2001 From: Dominic Masters Date: Sun, 1 Jul 2018 11:17:29 +1000 Subject: [PATCH] Server now works and compiles --- package.json | 37 ++--- private/app/App.js | 6 + private/server/Server.js | 37 ++++- private/server/WebpackCompilerOptions.js | 127 ++++++++++++++++++ public/App.jsx | 6 +- public/animation/fade/ElementScrollFader.jsx | 1 + .../about/sections/ExistingWorkSection.jsx | 2 +- 7 files changed, 195 insertions(+), 21 deletions(-) create mode 100644 private/server/WebpackCompilerOptions.js diff --git a/package.json b/package.json index fa51de3..5543f6d 100644 --- a/package.json +++ b/package.json @@ -24,6 +24,19 @@ }, "homepage": "https://github.com/YourWishes/domsPlaceNew#readme", "dependencies": { + "babel-core": "^6.26.3", + "babel-loader": "^7.1.4", + "babel-polyfill": "^6.26.0", + "babel-preset-env": "^1.7.0", + "babel-preset-react": "^6.24.1", + "body-parser": "^1.18.3", + "compression-webpack-plugin": "^1.1.11", + "css-loader": "^0.28.11", + "express": "^4.16.3", + "file-loader": "^1.1.11", + "html-webpack-plugin": "^3.2.0", + "mini-css-extract-plugin": "^0.4.1", + "node-sass": "^4.9.0", "pg-promise": "^8.4.4", "react": "^16.4.0", "react-dom": "^16.4.0", @@ -33,23 +46,15 @@ "react-router-dom": "^4.3.1", "react-tap-event-plugin": "^3.0.3", "react-transition-group": "^2.3.1", - "redux": "^4.0.0" + "redux": "^4.0.0", + "sass-loader": "^7.0.3", + "style-loader": "^0.21.0", + "uglifyjs-webpack-plugin": "^1.2.7", + "url-loader": "^1.0.1", + "webpack": "^4.14.0" }, "devDependencies": { - "babel-core": "^6.26.3", - "babel-loader": "^7.1.4", - "babel-polyfill": "^6.26.0", - "babel-preset-env": "^1.6.1", - "babel-preset-react": "^6.24.1", - "css-loader": "^0.28.11", - "file-loader": "^1.1.11", - "html-webpack-plugin": "^3.2.0", - "node-sass": "^4.9.0", - "react-hot-loader": "^4.1.2", - "sass-loader": "^7.0.1", - "style-loader": "^0.21.0", - "url-loader": "^1.0.1", - "webpack": "^3.11.0", - "webpack-dev-server": "^2.9.1" + "react-hot-loader": "^4.3.3", + "webpack-dev-server": "^3.1.4" } } diff --git a/private/app/App.js b/private/app/App.js index 4bd7f9a..d894815 100644 --- a/private/app/App.js +++ b/private/app/App.js @@ -21,12 +21,17 @@ // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. +//Imports const + path = require('path'), ConfigurationManager = require('./../configuration/ConfigurationManager'), DatabaseConnection = require('./../database/DatabaseConnection'), Server = require('./../server/Server') ; +//Constants +const PUBLIC_PATH = path.join(__dirname, '..', '..', 'dist'); + class App { constructor() { @@ -34,6 +39,7 @@ class App { getConfig() { return this.config; } getDatabase() { return this.db; } + getPublicDirectory() { return PUBLIC_PATH; } //Primary Functions async start() { diff --git a/private/server/Server.js b/private/server/Server.js index fc1e097..1b3c4de 100644 --- a/private/server/Server.js +++ b/private/server/Server.js @@ -27,9 +27,15 @@ const https = require('https'), express = require('express'), bodyParser = require('body-parser'), - fs = require('fs') + fs = require('fs'), + path = require('path'), + webpack = require('webpack'), + CompilerOptions = require('./WebpackCompilerOptions') ; +//Constants +const LANDING_FILE = 'index.html'; + class Server { constructor(app) { this.app = app; @@ -66,6 +72,7 @@ class Server { throw new Error("Invalid SSL Cert in Server Configuration"); } + //TODO: Clean this up, don't use static files (use path.join etc) and should these be flat files? let keyFile = __dirname+'./../'+this.config.ssl.key; let certFile = __dirname+'./../'+this.config.ssl.cert; if(!fs.existsSync(keyFile)) { @@ -89,6 +96,10 @@ class Server { this.express.use(bodyParser.urlencoded({ extended: true })); + this.express.use(express.static('./dist')); + + //Finally our catcher for all other enquiries + this.express.get('*', this.onGetRequest.bind(this)); //Create our HTTP and (if needed HTTPS) server(s) this.http = http.createServer(this.express); @@ -104,6 +115,9 @@ class Server { }, this.express); this.https.on('error', this.onServerError.bind(this)); } + + //Create our bundler + this.compiler = webpack(CompilerOptions(this, this.app)); } getConfig() {return this.config;} @@ -114,6 +128,7 @@ class Server { getHTTPSPort() {return this.portHTTPS;} getKey() {return this.key;} getCertificate() {return this.cert;} + getLandingFile() {return path.join(this.app.getPublicDirectory(), LANDING_FILE);} isRunning() { if(typeof this.http !== typeof undefined) { @@ -140,6 +155,11 @@ class Server { port: this.port }; + //Create our webpack watcher + this.watcher = this.compiler.watch({ + + }, this.onWatchChange.bind(this)); + //Start the HTTP Server this.http.listen(options, this.onServerStart.bind(this)); @@ -172,12 +192,18 @@ class Server { delete this.http; delete this.https; delete this.stopPromise; + delete this.watcher; } stopPromise(resolve, reject) { this.stopResolve = resolve; this.stopReject = reject; + if(typeof this.watcher !== typeof undefined) { + this.watcher.close(() => { + }); + } + try { this.http.close(this.onHTTPClosed.bind(this)); } catch(e) { @@ -201,6 +227,15 @@ class Server { onHTTPSClosed() { this.resolve(); } + + onWatchChange(error, stats) { + if(error) console.log(error); + } + + onGetRequest(req, res) { + //Used as our "catch all get requests" + res.sendFile(this.getLandingFile()); + } } module.exports = Server; diff --git a/private/server/WebpackCompilerOptions.js b/private/server/WebpackCompilerOptions.js new file mode 100644 index 0000000..6c4edbf --- /dev/null +++ b/private/server/WebpackCompilerOptions.js @@ -0,0 +1,127 @@ +// Copyright (c) 2018 Dominic Masters +// +// MIT License +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +//Includes +const + path = require('path'), + webpack = require('webpack'), + HtmlWebpackPlugin = require('html-webpack-plugin'), + CompressionPlugin = require("compression-webpack-plugin"), + UglifyJsPlugin = require('uglifyjs-webpack-plugin'), + MiniCssExtractPlugin = require("mini-css-extract-plugin") +; + +//Constants +const SOURCE_DIRECTORY = './public'; +const ENTRY_FILE = 'index.jsx'; +const ENTRY_WRAPPER = 'index.html'; + +module.exports = function(server, app) { + //Create our dirs + let entryDir = path.join(app.getPublicDirectory(), '..', 'public'); + + //Create our output + let output = {}; + + //Set the entry point + output.entry = path.join(entryDir, ENTRY_FILE); + + //Set the output + output.output = { + path: app.getPublicDirectory(), + filename: "app.js" + } + + //Set Resolves + output.resolve = { + modules: ['node_modules', SOURCE_DIRECTORY], + extensions: ['.js', '.jsx', '.css', '.scss' ] + }; + + //Setup Modules + output.module = { + rules: [ + { + test: /\.jsx?$/, + exclude: /node_modules/, + loaders: ['babel-loader'] + }, + { + test: /\.scss$|\.css$/i, + use: [ + MiniCssExtractPlugin.loader, + "css-loader", + 'sass-loader', + ] + }, + + { + test: /\.jpe?g$|\.gif$|\.png$|\.svg|\.webm|\.mp4$/i, + loader: "file-loader?name=[path][name].[ext]" + }, + + { + test: /\.(eot|ttf|woff(2)?)(\?v=\d+\.\d+\.\d+)?/, + loader: 'url-loader' + } + ] + }; + + //Setup the Plugins + let HTMLWebpackPluginConfig = new HtmlWebpackPlugin({ + template: path.join(SOURCE_DIRECTORY, ENTRY_WRAPPER), + filename: ENTRY_WRAPPER, + inject: true + }); + + let UglifyPluginConfig = new UglifyJsPlugin({ + test: /\.js($|\?)/i + }); + + let MiniCssExtractConfig = new MiniCssExtractPlugin({ + filename: "[name].css", + chunkFilename: "[id].css" + }) + + //Set the plugins + output.plugins = [ + new webpack.DefinePlugin({ + 'process.env.NODE_ENV': JSON.stringify('production') + }), + MiniCssExtractConfig, + HTMLWebpackPluginConfig + ]; + + //Minimization + output.optimization = { + minimize: true, + minimizer: [ + UglifyPluginConfig + ] + }; + + //Now setup the production values + output.devtool = 'source-map'; + + return output; +} diff --git a/public/App.jsx b/public/App.jsx index 84f1f0c..64e590d 100644 --- a/public/App.jsx +++ b/public/App.jsx @@ -27,7 +27,7 @@ import { connect } from 'react-redux'; import Background from './background/Background'; import Header from './header/Header'; import Footer from './footer/Footer'; -import { HashRouter } from 'react-router-dom'; +import { HashRouter, BrowserRouter } from 'react-router-dom'; import Routes from './page/Routes'; class App extends React.Component { @@ -50,12 +50,12 @@ class App extends React.Component { if(this.props.menuOpen) clazz += " is-menu-open " return ( - +
-
+ ); } } diff --git a/public/animation/fade/ElementScrollFader.jsx b/public/animation/fade/ElementScrollFader.jsx index fc61ea4..322e54c 100644 --- a/public/animation/fade/ElementScrollFader.jsx +++ b/public/animation/fade/ElementScrollFader.jsx @@ -57,6 +57,7 @@ class ElementScrollFader extends React.Component { } checkEffect() { + if(typeof window === typeof undefined) return; if(!this.refs || !this.refs.fader) return; //Get bounds var rect = this.refs.fader.getBoundingClientRect(); diff --git a/public/page/about/sections/ExistingWorkSection.jsx b/public/page/about/sections/ExistingWorkSection.jsx index c95719d..291ec9a 100644 --- a/public/page/about/sections/ExistingWorkSection.jsx +++ b/public/page/about/sections/ExistingWorkSection.jsx @@ -41,7 +41,7 @@ import Window95, { const ExistingWorkFrame = (props) => { let fakeURL = props.href; - if(!fakeURL.startsWith("http")) { + if(!fakeURL.startsWith("http") && typeof window !== typeof undefined) { fakeURL = window.location.protocol + fakeURL; }