diff --git a/README.md b/README.md index 8f00333..3c8a6db 100644 --- a/README.md +++ b/README.md @@ -33,7 +33,7 @@ The PRD really sttarted kit for **ReactJs** with hot module replacement (HMR) fo Based on the best practises of the Single-Page-Application development with NodeJS. I added the nice font-end component [Material-Dashboard-React](https://github.com/creativetimofficial/material-dashboard-react) and Redux store integration. -Beside of that I also developped some useful compoment as Message box, Notification to make the Started-kit to be a **Production ready** SPA. +Beside of that I also developped some useful compoment as Message box, Notification to make the Started-kit to be a **Production ready** SPA kit. ## Support Features @@ -61,15 +61,13 @@ async function getDataFromServer() { } ``` -### Installation +## Installation 1. Clone/download repo 2. `npm install` 3. Replace the CodeCov.io token to your one in the `package.json` file. 4. Run `npm start` to run the project. ---- - ## Usage ### Development @@ -92,12 +90,12 @@ async function getDataFromServer() { - Analysis served @ `http://localhost:8888` ---- - ## New Compoments 1. **Message Box and Notification**: Allow to show Info, Confirm, Success and Error message and notification. Refer to the MessageBox in Views folder so sample that using Redux store to manage the state. +## Environment Supports + ### Docker Support 1. Build Image `docker build`. @@ -106,36 +104,42 @@ async function getDataFromServer() { 3. Push inage to Docker hub `docker push [YOUR_ID]/react-materialui-started-kit:latest` Example `docker push baoduy2412/react-materialui-started-kit:latest`. -The application will running port 3000 in Docker. +The application will running port 80 and 443 in Docker. The image can be found in Docker hub [here](https://hub.docker.com/r/baoduy2412/react-materialui-started-kit/). -**If you are using Docker the `Docker` folder in this project can be deleted without any impact.** - ---- +However if you are not using Docker just simply remove the submodule **sm-react-docker-nginx** There is no impact to the application. ### IIS Support -The `Web.config` file had been added for IIS hosting purpose. When build the application this file will be copied to dist folder automatically and make the package ready for IIS. +The `Web.config` file in **sm-react-iis** had been added for IIS hosting purpose. This file should be copy along with all files in dist folder when hosting in IIS. -However if you are not hosting this app in IIS just simply delete this file.or leave if there. There is no impact to the application. +However if you are not hosting this app in IIS just simply remove the submodule **sm-react-iis** There is no impact to the application. ### Azure Service Fabric Support -All stuffs in `service-fabric` folder are using for **[Azure Service Fabric](https://azure.microsoft.com/en-us/services/service-fabric/)** hosting purpose. -The project inside this folder will copy all files in dist folder and host as a static side in Azure Service Fabric. -I'm using .Net Core 2.0 to make the project is flexible enough to host on any platforms. +All stuffs in `sm-react-service-fabric` folder are using for **[Azure Service Fabric](https://azure.microsoft.com/en-us/services/service-fabric/)** hosting purpose. + +The C# project inside this folder will copy all files from dist folder to wwwroot folder and host them as a static side in Azure Service Fabric. + +Currently, I'm using .Net Core 2.1 to make the project is flexible enough to host on any platforms. When build the Service Fabric application it will copy all files in `dist` folder to `wwwroot` folder. So ensure you run the `npm build` before deploy the Service Fabric app. -Defiantly, If you are not using **Azure Service Fabric**. This folder shall be deleted. +However if you are not using Service Fabric just simply remove the submodule **sm-react-service-fabric** There is no impact to the application. + +### Node Js Hosting + +There is a sub module contains the Express.js configuration to host the application in the Node Js environment. +The application will running port 3000 and 3001 in NodeJs and the port is configurable in the Js file. + +If you are not using Node Js hosting just simply remove the submodule **sm-react-node-express** There is no impact to the application. +But, please note that the `npm run start-prod` is using this submodule to hosting the dist folder as a static side. Please be considered before removing this module. ### GZIP and SSL The **GZIP** and **SSL** had been applied for all hosting environments above. ---- - -### All commands +## All commands | Command | Description | | ------------------------ | ------------------------------------------------------------------------ | diff --git a/configs/jest b/configs/jest index 9b59a48..5195b1c 160000 --- a/configs/jest +++ b/configs/jest @@ -1 +1 @@ -Subproject commit 9b59a48bd805e449951a69c6dcafa32e841cd05b +Subproject commit 5195b1c397fbac880b5fe235816b699f743dd8a6 diff --git a/sm-react-service-fabric b/sm-react-service-fabric index 743d4db..06d016f 160000 --- a/sm-react-service-fabric +++ b/sm-react-service-fabric @@ -1 +1 @@ -Subproject commit 743d4db4bfaeae72bfcfd91d1f311f82749f4bfe +Subproject commit 06d016f01a8d9b7de666101403ab153ade667db2 diff --git a/src/commons/commonFuncs.js b/src/commons/commonFuncs.js index 5bc0ce6..90d9c8b 100644 --- a/src/commons/commonFuncs.js +++ b/src/commons/commonFuncs.js @@ -1,21 +1,43 @@ +/*eslint no-console: ["off", { allow: ["warn", "error"] }] */ + import linq from 'linq'; import uuidv4 from 'uuid/v4'; //correct URL for Reserved proxy //Get the millisecond of current time. +export function GetBaseUrl() { + const key = 'BASE_URL'; + let base = window.sessionStorage.getItem(key); + + if (base === undefined || base === null) { + base = document.getElementsByTagName('base')[0].getAttribute('href'); + window.sessionStorage.setItem(key, base); + + console.log(`base URL is ${base}`); + } + + return base; +} + export function newGuid() { return uuidv4(); } - +/** + *getImgSrc for both normal hosting and Reverse proxy + * + * @export + * @param {string} url the relative image url + * @returns real url + */ export function getImgSrc(url) { if (typeof url !== 'string') return url; - const base = window._base; - - if (!base || base === '/') return url; - if (url.indexOf(base) >= 0) return url; + const base = GetBaseUrl(); - return `${base}/${url}`; + return !base || base === '/' || url.indexOf(base) >= 0 + ? url + : `${base}/${url}`; } + /** *Merge second array to first array if existed then update. * diff --git a/src/index.jsx b/src/index.jsx index c8a1909..c72f6f9 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -1,10 +1,11 @@ -/*eslint no-console: ["off", { allow: ["warn", "error"] }] */ import React from 'react'; import ReactDOM from 'react-dom'; import { createBrowserHistory } from 'history'; import { Router, Route, Switch, BrowserRouter } from 'react-router-dom'; import Provider from 'react-redux-thunk-store'; import ExceptionHandler from './layouts/ExceptionHandler'; + +import { GetBaseUrl } from './commons/commonFuncs'; //Style-sheets import './assets/less/material-dashboard-react.less'; @@ -15,14 +16,12 @@ import indexRoutes from 'routes/index.jsx'; const isPrd = process.env.NODE_ENV === 'production'; //Update for Reserved proxy -window._base = document.getElementsByTagName('base')[0].getAttribute('href'); -console.log(`base URL ${window._base}`); - -const hist = createBrowserHistory({ basename: window._base }); +const base = GetBaseUrl(); +const hist = createBrowserHistory({ basename: base }); const createRouter = () => { return ( - + {indexRoutes.map((prop, key) => { diff --git a/tests/commons/commonFuncs.test.js b/tests/commons/commonFuncs.test.js index 26a7868..d116dec 100644 --- a/tests/commons/commonFuncs.test.js +++ b/tests/commons/commonFuncs.test.js @@ -1,36 +1,37 @@ -import { getImgSrc, newGuid } from "../../src/commons/commonFuncs"; +import { getImgSrc, newGuid } from '../../src/commons/commonFuncs'; -test("2 GUID must be difference", () => { +window.sessionStorage.setItem('BASE_URL', '/ReactJs'); + +test('2 GUID must be difference', () => { const g1 = newGuid(); const g2 = newGuid(); expect(g1).not.toBe(g2); }); -test("getImgSrc should add basename to url", () => { - window._base = "/ReactJs"; - expect(getImgSrc("/img/a.png")).toContain(window._base); +test('getImgSrc should add basename to url', () => { + expect(getImgSrc('/img/a.png')).toContain('/ReactJs'); }); -test("getImgSrc should not add basename to url", () => { - window._base = "/ReactJs"; - expect(getImgSrc("/ReactJs/img/a.png")).toBe("/ReactJs/img/a.png"); +test('getImgSrc should not add basename to url', () => { + expect(getImgSrc('/ReactJs/img/a.png')).toBe('/ReactJs/img/a.png'); }); -test("getImgSrc should return original object", () => { - window._base = "/ReactJs"; +test('getImgSrc should return original object', () => { const url = { a: 1 }; expect(getImgSrc(url)).toBe(url); }); -test("getImgSrc should return original string", () => { - window._base = "/"; - const url = "123"; +test('getImgSrc should return original string', () => { + const url = '123'; + window.sessionStorage.setItem('BASE_URL', '/'); + expect(getImgSrc(url)).toBe(url); }); -test("getImgSrc should do nothing", () => { - window._base = undefined; - const url = "123"; +test('getImgSrc should do nothing', () => { + const url = '123'; + window.sessionStorage.setItem('BASE_URL', ''); + expect(getImgSrc(url)).toBe(url); });