Skip to content

Commit

Permalink
Merge 92478dc into b945f18
Browse files Browse the repository at this point in the history
  • Loading branch information
taniarascia committed Feb 22, 2020
2 parents b945f18 + 92478dc commit 8866991
Show file tree
Hide file tree
Showing 10 changed files with 115 additions and 34 deletions.
3 changes: 2 additions & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ script:
- npm run coveralls && npm run e2e

deploy:
# Build Docker container and push to Dockerhub
# Build Docker container and push to Docker Hub
# Pull into DigitalOcean container and start
provider: script
script: bash deploy.sh
on:
Expand Down
3 changes: 2 additions & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ FROM node:12-alpine

# Set environment variables
ENV PORT=5000
ARG CLIENT_ID

COPY . app/

Expand All @@ -19,7 +20,7 @@ RUN apk add --no-cache \
libpng-dev \
make \
nasm
RUN npm ci --only-production
RUN npm ci --only-production --silent

# Build production client side React application
RUN npm run build
Expand Down
69 changes: 60 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,6 @@ npm i
In the development environment, an Express server is running on port `5000` to handle all API calls, and a hot Webpack dev server is running on port `3000` for the React front end. To run both of these servers concurrently, run the `dev` command.

```bash
# Run client and server concurrently
npm run dev
```

Expand All @@ -87,26 +86,24 @@ API requests will be proxied to port `5000` automatically.
In production, the React app is built, and Express redirects all incoming requests to the `dist` directory on port `5000`.

```bash
# Build client for production and start server
npm run build && npm run start
```

Go to `localhost:5000` to view the app.

### Run in Docker

Docker containers are [also available on the Dockerhub registry](https://hub.docker.com/r/taniarascia/takenote).

> Note: You'll have to pass the client id, client secret, and ensure `secure: false` is set on the cookie.
Follow these instructions to build an image and run a container.

```bash
# Build image and run container
docker build -t takenote .
docker run --env-file .env -p 5000:5000 takenote
docker build --build-arg CLIENT_ID=xxx -t takenote:mytag .
docker run -p CLIENT_ID=xxx CLIENT_SECRET=xxxx NODE_ENV=development 5000:5000 takenote:mytag
```

Go to `localhost:5000` to view the app.

> Note: You will see some errors during the installation phase, but these are simply warnings that unnecessary packages do not exist, since the Node Alpine base image is minimal.
### Seed data

To seed the app with some test data, paste the contents of `seed.js` into your browser console.
Expand All @@ -122,9 +119,63 @@ npm run test
Run Cypress e2e tests.

```bash
npm run cypress:open
npm run e2e:open
```

## Folder Structure

```bash
├── config
│ ├── webpack.common.js # Webpack shared configuration
│ ├── webpack.dev.js # Webpack development configuration (dev server)
│ └── webpack.prod.js # Webpack productuon configuration (dist output)
├── cypress # End-to-end tests
├── docs # Assets for documentation
├── patches # Overrides for dependencies
├── public # Files that will write to dist on build
├── src
│ ├── client # React client side code
│ └── server # Node/Express server side code
├── .editorconfig # Configures editor rules
├── .gitattributes # Additional git attributes
├── .gitignore # Lists files for git to ignore
├── .prettierrc # Code convention enforced by Prettier
├── .travis.yml # Continuous integration and deployment config
├── CHANGELOG.md # List of significant changes
├── cypress.json # Cypress configuration
├── deploy.sh # Deployment script for Docker in production
├── Dockerfile # Docker build instructions
├── jest.config.js # Jest configuration
├── LICENSE # License for this open source project
├── nodemon.json # Nodemon configuration
├── package-lock.json # Package lockfile
├── package.json # Dependencies and additional information
├── README.md
├── seed.js # Seed the app with data for testing
├── seed.js # Seed the app with data for testing
├── tsconfig.json # Typescript configuration
└── tsconfig.test.json # Typescript test configuration
```

## Technologies

TakeNote is possible thanks the all these open source languages, libraries, and frameworks.

| Tech | Description |
| --------------------------------------------- | ----------------------------------------- |
| [Codemirror](https://codemirror.net/) | Browser-based text editor |
| [TypeScript](https://www.typescriptlang.org/) | Static type-checking programming language |
| [Node.js](https://nodejs.org/en/) | JavaScript runtime for the backend |
| [Express](https://expressjs.com/) | Server framework |
| [React](https://reactjs.org/) | Front end user interface |
| [Redux](https://redux.js.org/) | Global state management |
| [Webpack](https://webpack.js.org/) | Asset bundler |
| [Sass](https://sass-lang.com/) | Style preprocessor |
| [OAuth](https://oauth.net/) | Protocol for secure authorization |
| [ESLint](https://eslint.org/) | TypeScript linting |
| [Jest](https://jestjs.io/) | Unit testing framework |
| [Cypress](https://www.cypress.io/) | End-to-end testing framework | L |

## Contributing

TakeNote is an open source project, and contributions of any kind are welcome! Open issues, bugs, and enhancements are all listed on the [issues](https://github.com/taniarascia/takenote/issues) tab and labeled accordingly. Feel free to open bug tickets and make feature requests. Easy bugs and features will be tagged with the `good first issue` label.
Expand Down
35 changes: 14 additions & 21 deletions config/webpack.common.js
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
const path = require('path')

const webpack = require('webpack')
const dotenv = require('dotenv')
const webpack = require('webpack')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

// Obtain CLIENT_ID for OAuth link
// Hard code client ID for deployment due to difficulties passing in env file
const envVariable = dotenv.config()
/**
* Obtain client id for OAuth link in React
*
* If in development mode or local production mode, search the .env file for
* client id. If using Docker, pass a build arg.
*
*/
const getEnvFromDotEnvFile = dotenv.config()
let envKeys
if (envVariable.error) {
if (getEnvFromDotEnvFile.error) {
console.log('Getting environment variables from build args for production') // eslint-disable-line
envKeys = {
'process.env.CLIENT_ID': '"a6f0527550d66198cedf"',
'process.env.CLIENT_ID': JSON.stringify(process.env.CLIENT_ID),
'process.env.NODE_ENV': JSON.stringify('production'),
}
} else {
envKeys = {
'process.env.CLIENT_ID': JSON.stringify(envVariable.parsed['CLIENT_ID']),
}
envKeys = { 'process.env.CLIENT_ID': JSON.stringify(getEnvFromDotEnvFile.parsed['CLIENT_ID']) }
}

module.exports = {
Expand Down Expand Up @@ -111,16 +115,5 @@ module.exports = {
ignore: ['*.DS_Store', 'favicon.ico', 'template.html'],
},
]),

/**
* HtmlWebpackPlugin
*
* Generates the React SPA HTML file from a template.
*/
new HtmlWebpackPlugin({
template: './public/template.html',
favicon: './public/favicon.ico',
hash: true,
}),
],
}
11 changes: 11 additions & 0 deletions config/webpack.dev.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const webpack = require('webpack')
const merge = require('webpack-merge')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const common = require('./webpack.common.js')

Expand Down Expand Up @@ -79,5 +80,15 @@ module.exports = merge(common, {
* the whole page.
*/
new webpack.HotModuleReplacementPlugin(),

/**
* HtmlWebpackPlugin
*
* Generates the React SPA HTML file from a template.
*/
new HtmlWebpackPlugin({
template: './public/template.html',
favicon: './public/favicon.ico',
}),
],
})
22 changes: 22 additions & 0 deletions config/webpack.prod.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,19 @@ const merge = require('webpack-merge')
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const TerserJSPlugin = require('terser-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const common = require('./webpack.common.js')

// Disable React DevTools in production
const disableReactDevtools = `
<script>
if (typeof window.__REACT_DEVTOOLS_GLOBAL_HOOK__ === 'object') {
__REACT_DEVTOOLS_GLOBAL_HOOK__.inject = function() {};
}
</script>
`

module.exports = merge(common, {
/**
* Mode
Expand Down Expand Up @@ -72,6 +82,18 @@ module.exports = merge(common, {
chunkFilename: 'styles/[name].[id].[hash].css',
ignoreOrder: false,
}),

/**
* HtmlWebpackPlugin
*
* Hash the HTML so it registers every new version, and disable React DevTools.
*/
new HtmlWebpackPlugin({
template: './public/template.html',
favicon: './public/favicon.ico',
hash: true,
disableReactDevtools,
}),
new webpack.SourceMapDevToolPlugin({
exclude: ['/node_modules/'],
}),
Expand Down
2 changes: 1 addition & 1 deletion deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ GIT_VERSION=$(git describe --always --abbrev --tags --long)
# Build and tag new Docker image and push up to Docker Hub
echo "Building and tagging new Docker image: ${IMAGE}:${GIT_VERSION}"

docker build -t ${IMAGE}:${GIT_VERSION} .
docker build --build-arg CLIENT_ID=${CLIENT_ID} -t ${IMAGE}:${GIT_VERSION} .
docker tag ${IMAGE}:${GIT_VERSION} ${IMAGE}:latest

# Login to Docker Hub and push newest build
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"client": "cross-env NODE_ENV=development webpack-dev-server --config config/webpack.dev.js",
"server": "nodemon",
"build": "cross-env NODE_ENV=production webpack --config config/webpack.prod.js",
"start": "cross-env NODE_ENV=production node -r ts-node/register/transpile-only src/server/index.ts",
"start": "node -r ts-node/register/transpile-only src/server/index.ts",
"test": "jest",
"coveralls": "jest --ci --coverage --watchAll=false && cat ./coverage/lcov.info | coveralls",
"e2e": "cypress run",
Expand Down
1 change: 1 addition & 0 deletions public/template.html
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
</head>

<body>
<%= htmlWebpackPlugin.options.disableReactDevtools %>
<div id="root"></div>
</body>

Expand Down
1 change: 1 addition & 0 deletions src/client/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ const sagaMiddleware = createSagaMiddleware()
const store = configureStore({
reducer: rootReducer,
middleware: [sagaMiddleware, ...getDefaultMiddleware({ thunk: false })],
devTools: process.env.NODE_ENV !== 'production',
})

sagaMiddleware.run(rootSaga)
Expand Down

0 comments on commit 8866991

Please sign in to comment.