├── .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.scss │ └── views │ │ └── index.html └── server │ ├── index.js │ └── mockAPI.js ├── webpack.dev.js └── webpack.prod.js /.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 ND0044 C2 | 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":"nd0044- Full Stack Nanodegree"}], "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 | dist 2 | node_modules 3 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @udacity/active-public-content 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Webpack Express With Sass 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 want to follow along, start from branch 0-initial-setup. 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. 6 | 7 | ## What we will cover 8 | 9 | We will cover: 10 | 11 | - Transpiling Sass to CSS using Webpack 12 | - Fixing Javascript event errors 13 | - Building a better production config for Webpack 14 | - Adding Service Workers to our app using Webpack 15 | 16 | ## Get Up and Running 17 | 18 | Fork this repo, then clone the branch of your choice from your forked repo down to your computer: 19 | 20 | ``` 21 | git clone https://github.com//fend-webpack-sass.git 22 | ``` 23 | 24 | `cd` into your new folder and run: 25 | - ```npm install``` 26 | - ```npm run build-dev``` to start the webpack dev server 27 | - ```npm run build-prod``` to generate a dist folder for prod 28 | - ```npm start``` to run the Express server on port 8081 29 | -------------------------------------------------------------------------------- /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-sass/41fb565f2bade2f74f98ca6634c4c832ef2d4f84/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.scss: -------------------------------------------------------------------------------- 1 | /* http://meyerweb.com/eric/tools/css/reset/ 2 | v2.0 | 20110126 3 | License: none (public domain) 4 | */ 5 | 6 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td, article, aside, canvas, details, embed, figure, figcaption, footer, header, hgroup, menu, nav, output, ruby, section, summary, time, mark, audio, video { 7 | margin: 0; 8 | padding: 0; 9 | border: 0; 10 | font-size: 100%; 11 | font: inherit; 12 | vertical-align: baseline; 13 | } 14 | 15 | /* HTML5 display-role reset for older browsers */ 16 | 17 | article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section { 18 | display: block; 19 | } 20 | 21 | body { 22 | line-height: 1; 23 | } 24 | 25 | ol, ul { 26 | list-style: none; 27 | } 28 | 29 | blockquote, q { 30 | quotes: none; 31 | 32 | &:before, &:after { 33 | content: ''; 34 | content: none; 35 | } 36 | } 37 | 38 | table { 39 | border-collapse: collapse; 40 | border-spacing: 0; 41 | } 42 | -------------------------------------------------------------------------------- /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 | --------------------------------------------------------------------------------