├── .babelrc ├── .github └── workflows │ └── manual.yml ├── .gitignore ├── CODEOWNERS ├── README.md ├── package-lock.json ├── package.json ├── src ├── client │ ├── index.js │ ├── js │ │ ├── formHandler.js │ │ └── nameChecker.js │ ├── styles │ │ ├── base.css │ │ ├── footer.css │ │ ├── form.css │ │ ├── header.css │ │ └── resets.css │ └── views │ │ └── index.html └── server │ ├── index.js │ └── mockAPI.js ├── webpack.dev.js └── webpack.prod.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | 'presets': ['@babel/preset-env'] 3 | } 4 | -------------------------------------------------------------------------------- /.github/workflows/manual.yml: -------------------------------------------------------------------------------- 1 | # Workflow to ensure whenever a Github PR is submitted, 2 | # a JIRA ticket gets created automatically. 3 | name: Manual Workflow 4 | 5 | # Controls when the action will run. 6 | on: 7 | # Triggers the workflow on pull request events but only for the master branch 8 | pull_request_target: 9 | types: [opened, reopened] 10 | 11 | # Allows you to run this workflow manually from the Actions tab 12 | workflow_dispatch: 13 | 14 | jobs: 15 | test-transition-issue: 16 | name: Convert Github Issue to Jira Issue 17 | runs-on: ubuntu-latest 18 | steps: 19 | - name: Checkout 20 | uses: actions/checkout@master 21 | 22 | - name: Login 23 | uses: atlassian/gajira-login@master 24 | env: 25 | JIRA_BASE_URL: ${{ secrets.JIRA_BASE_URL }} 26 | JIRA_USER_EMAIL: ${{ secrets.JIRA_USER_EMAIL }} 27 | JIRA_API_TOKEN: ${{ secrets.JIRA_API_TOKEN }} 28 | 29 | - name: Create NEW JIRA ticket 30 | id: create 31 | uses: atlassian/gajira-create@master 32 | with: 33 | project: CONUPDATE 34 | issuetype: Task 35 | summary: | 36 | Github PR ND0011 C5 | Repo: ${{ github.repository }} | PR# ${{github.event.number}} 37 | description: | 38 | Repo link: https://github.com/${{ github.repository }} 39 | PR no. ${{ github.event.pull_request.number }} 40 | PR title: ${{ github.event.pull_request.title }} 41 | PR description: ${{ github.event.pull_request.description }} 42 | In addition, please resolve other issues, if any. 43 | fields: '{"components": [{"name":"nd0011 - Front End Developer"}], "customfield_16449":"https://classroom.udacity.com/", "customfield_16450":"Resolve the PR", "labels": ["github"], "priority":{"id": "4"}}' 44 | 45 | - name: Log created issue 46 | run: echo "Issue ${{ steps.create.outputs.issue }} was created" 47 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @udacity/active-public-content 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Webpack Express Example App 2 | 3 | The goal of this repo is be an example of a basic but functional app built on Express and Webpack. 4 | 5 | If you are just starting this process, start from branch 0-initial-setup. Otherwise, switch to the appropriate numbered branches of this repo as needed. The branches are: 6 | - [0-initial-setup](https://github.com/udacity/fend-webpack-content/tree/0-initial-setup) 7 | - [1-install-webpack](https://github.com/udacity/fend-webpack-content/tree/1-install-webpack) 8 | - [2-add-webpack-entry](https://github.com/udacity/fend-webpack-content/tree/2-add-webpack-entry) 9 | - [3-webpack-output-and-loaders](https://github.com/udacity/fend-webpack-content/tree/3-webpack-output-and-loaders) 10 | - [4-webpack-plugins](https://github.com/udacity/fend-webpack-content/tree/4-webpack-plugins) 11 | - [5-webpack-mode](https://github.com/udacity/fend-webpack-content/tree/5-webpack-mode) 12 | - [6-webpack-for-convenience](https://github.com/udacity/fend-webpack-content/tree/6-webpack-for-convenience) 13 | 14 | Each branch in this project is a step along the path to creating a fully functional webpack setup. In each branch, there will be a documentation file that lists out the steps taken in that branch (each step is also roughly a git commit if you look at the history) which you can use as a checklist when setting up your own projects. 15 | 16 | ## What we will cover 17 | 18 | We will cover: 19 | 20 | - Webpack entry point 21 | - Webpack output and dist folder 22 | - Webpack Loaders 23 | - Webpack Plugins 24 | - Webpack Mode 25 | - Tools for convenient Webpack development 26 | 27 | ## Get Up and Running 28 | 29 | Fork this repo, then clone the branch of your choice from your forked repo down to your computer: 30 | 31 | ``` 32 | git clone -- git@github.com:[your-user-name]/webpack-express.git -- 33 | ``` 34 | 35 | `cd` into your new folder and run: 36 | - ```npm install``` 37 | - ```npm start``` to start the app 38 | - this app runs on localhost:8080, but you can of course edit that in server.js 39 | 40 | **Note:** Webpack needs to be at version 4 in order for this repo to work as expected. Webpack is automatically included at the correct version in the `package.json` provided here. 41 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example-project", 3 | "version": "1.0.0", 4 | "main": "index.js", 5 | "scripts": { 6 | "test": "echo \"Error: no test specified\" && exit 1", 7 | "start": "node src/server/index.js", 8 | "build-prod": "webpack --config webpack.prod.js", 9 | "build-dev": "webpack-dev-server --config webpack.dev.js --open" 10 | }, 11 | "keywords": [], 12 | "author": "", 13 | "license": "ISC", 14 | "description": "", 15 | "dependencies": { 16 | "express": "^4.17.1", 17 | "webpack": "^4.35.3", 18 | "webpack-cli": "^3.3.5" 19 | }, 20 | "devDependencies": { 21 | "@babel/core": "^7.5.4", 22 | "@babel/preset-env": "^7.5.4", 23 | "babel-loader": "^8.0.6", 24 | "clean-webpack-plugin": "^3.0.0", 25 | "html-webpack-plugin": "^3.2.0", 26 | "webpack-dev-server": "^3.7.2" 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /src/client/index.js: -------------------------------------------------------------------------------- 1 | import { checkForName } from './js/nameChecker' 2 | import { handleSubmit } from './js/formHandler' 3 | 4 | console.log(checkForName); 5 | 6 | alert("I EXIST") 7 | console.log("CHANGE!!"); 8 | -------------------------------------------------------------------------------- /src/client/js/formHandler.js: -------------------------------------------------------------------------------- 1 | function handleSubmit(event) { 2 | event.preventDefault() 3 | 4 | // check what text was put into the form field 5 | let formText = document.getElementById('name').value 6 | checkForName(formText) 7 | 8 | console.log("::: Form Submitted :::") 9 | fetch('http://localhost:8080/test') 10 | .then(res => res.json()) 11 | .then(function(res) { 12 | document.getElementById('results').innerHTML = res.message 13 | }) 14 | } 15 | 16 | export { handleSubmit } 17 | -------------------------------------------------------------------------------- /src/client/js/nameChecker.js: -------------------------------------------------------------------------------- 1 | function checkForName(inputText) { 2 | console.log("::: Running checkForName :::", inputText); 3 | let names = [ 4 | "Picard", 5 | "Janeway", 6 | "Kirk", 7 | "Archer", 8 | "Georgiou" 9 | ] 10 | 11 | if(names.includes(inputText)) { 12 | alert("Welcome, Captain!") 13 | } 14 | } 15 | 16 | export { checkForName } 17 | -------------------------------------------------------------------------------- /src/client/styles/base.css: -------------------------------------------------------------------------------- 1 | body { 2 | display: flex; 3 | flex-direction: column; 4 | min-height: 100vh; 5 | } 6 | 7 | main { 8 | flex: 2; 9 | } 10 | 11 | section { 12 | max-width: 800px; 13 | margin: 50px auto; 14 | } 15 | -------------------------------------------------------------------------------- /src/client/styles/footer.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/udacity/fend-webpack-content/15cbe026357d5e9d79c9c32eef1d4a5fb10d33af/src/client/styles/footer.css -------------------------------------------------------------------------------- /src/client/styles/form.css: -------------------------------------------------------------------------------- 1 | form { 2 | border: 1px solid #545454; 3 | border-radius: 3px; 4 | padding: 40px; 5 | } 6 | 7 | input { 8 | padding: 5px 20px; 9 | width: 100%; 10 | line-height: 16px; 11 | margin: 10px 0; 12 | } 13 | -------------------------------------------------------------------------------- /src/client/styles/header.css: -------------------------------------------------------------------------------- 1 | header { 2 | display: flex; 3 | justify-content: space-between; 4 | padding: 10px 40px; 5 | } 6 | -------------------------------------------------------------------------------- /src/client/styles/resets.css: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | * { 7 | box-sizing: border-box; 8 | } 9 | 10 | html, body, div, span, applet, object, iframe, 11 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 12 | a, abbr, acronym, address, big, cite, code, 13 | del, dfn, em, img, ins, kbd, q, s, samp, 14 | small, strike, strong, sub, sup, tt, var, 15 | b, u, i, center, 16 | dl, dt, dd, ol, ul, li, 17 | fieldset, form, label, legend, 18 | table, caption, tbody, tfoot, thead, tr, th, td, 19 | article, aside, canvas, details, embed, 20 | figure, figcaption, footer, header, hgroup, 21 | menu, nav, output, ruby, section, summary, 22 | time, mark, audio, video { 23 | margin: 0; 24 | padding: 0; 25 | border: 0; 26 | font-size: 100%; 27 | font: inherit; 28 | vertical-align: baseline; 29 | } 30 | /* HTML5 display-role reset for older browsers */ 31 | article, aside, details, figcaption, figure, 32 | footer, header, hgroup, menu, nav, section { 33 | display: block; 34 | } 35 | body { 36 | line-height: 1; 37 | } 38 | ol, ul { 39 | list-style: none; 40 | } 41 | blockquote, q { 42 | quotes: none; 43 | } 44 | blockquote:before, blockquote:after, 45 | q:before, q:after { 46 | content: ''; 47 | content: none; 48 | } 49 | table { 50 | border-collapse: collapse; 51 | border-spacing: 0; 52 | } 53 | ul { 54 | list-style-type: none; 55 | } 56 | -------------------------------------------------------------------------------- /src/client/views/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Test 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 |
17 | Logo 18 |
19 |
20 | navigation 21 |
22 |
23 | 24 |
25 |
26 |
27 | 28 | 29 |
30 |
31 | 32 |
33 | Form Results: 34 |
35 |
36 |
37 | 38 | 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /src/server/index.js: -------------------------------------------------------------------------------- 1 | var path = require('path') 2 | const express = require('express') 3 | const mockAPIResponse = require('./mockAPI.js') 4 | 5 | const app = express() 6 | 7 | app.use(express.static('dist')) 8 | 9 | console.log(__dirname) 10 | 11 | app.get('/', function (req, res) { 12 | res.sendFile('dist/index.html') 13 | }) 14 | 15 | // designates what port the app will listen to for incoming requests 16 | app.listen(8080, function () { 17 | console.log('Example app listening on port 8080!') 18 | }) 19 | 20 | app.get('/test', function (req, res) { 21 | res.send(mockAPIResponse) 22 | }) 23 | -------------------------------------------------------------------------------- /src/server/mockAPI.js: -------------------------------------------------------------------------------- 1 | let json = { 2 | 'title': 'test json response', 3 | 'message': 'this is a message', 4 | 'time': 'now' 5 | } 6 | 7 | module.exports = json 8 | -------------------------------------------------------------------------------- /webpack.dev.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const webpack = require('webpack') 3 | const HtmlWebPackPlugin = require("html-webpack-plugin") 4 | const { CleanWebpackPlugin } = require('clean-webpack-plugin') 5 | 6 | module.exports = { 7 | entry: './src/client/index.js', 8 | mode: 'development', 9 | devtool: 'source-map', 10 | stats: 'verbose', 11 | module: { 12 | rules: [ 13 | { 14 | test: '/\.js$/', 15 | exclude: /node_modules/, 16 | loader: "babel-loader" 17 | } 18 | ] 19 | }, 20 | plugins: [ 21 | new HtmlWebPackPlugin({ 22 | template: "./src/client/views/index.html", 23 | filename: "./index.html", 24 | }), 25 | new CleanWebpackPlugin({ 26 | // Simulate the removal of files 27 | dry: true, 28 | // Write Logs to Console 29 | verbose: true, 30 | // Automatically remove all unused webpack assets on rebuild 31 | cleanStaleWebpackAssets: true, 32 | protectWebpackAssets: false 33 | }) 34 | ] 35 | } 36 | -------------------------------------------------------------------------------- /webpack.prod.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const webpack = require('webpack') 3 | const HtmlWebPackPlugin = require("html-webpack-plugin") 4 | 5 | module.exports = { 6 | entry: './src/client/index.js', 7 | mode: 'production', 8 | module: { 9 | rules: [ 10 | { 11 | test: '/\.js$/', 12 | exclude: /node_modules/, 13 | loader: "babel-loader" 14 | } 15 | ] 16 | }, 17 | plugins: [ 18 | new HtmlWebPackPlugin({ 19 | template: "./src/client/views/index.html", 20 | filename: "./index.html", 21 | }) 22 | ] 23 | } 24 | --------------------------------------------------------------------------------