├── .babelrc ├── .eslintrc ├── .github └── workflows │ └── greetings.yml ├── .gitignore ├── .travis.yml ├── README.md ├── __mocks__ └── fileMock.js ├── assets └── img │ ├── diversity.png │ ├── icons8-facebook 1.png │ └── logo.png ├── jest.config.json ├── package-lock.json ├── package.json ├── src ├── .eslintignore ├── declarations.d.ts ├── events │ ├── events.component.css │ ├── events.component.tsx │ └── events.resource.tsx ├── hocs │ ├── section.component.css │ └── section.component.tsx ├── home │ ├── banner.component.css │ ├── banner.component.spec.tsx │ ├── banner.component.tsx │ ├── home.component.css │ ├── home.component.spec.tsx │ └── home.component.tsx ├── index.css ├── index.html ├── index.tsx ├── navbar │ ├── navbar-links.ts │ ├── navbar.component.css │ └── navbar.component.tsx ├── opportunities │ ├── opportunities.component.css │ └── opportunities.component.tsx └── utils │ └── routing.tsx ├── tsconfig.json └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | "@babel/preset-env", 4 | "@babel/react", 5 | "@babel/preset-typescript", 6 | ], 7 | "plugins": [ 8 | "@babel/plugin-proposal-class-properties", 9 | ] 10 | } -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "extends": [ 4 | "ts-react-important-stuff", 5 | "plugin:prettier/recommended" 6 | ], 7 | "parser": "babel-eslint" 8 | } -------------------------------------------------------------------------------- /.github/workflows/greetings.yml: -------------------------------------------------------------------------------- 1 | name: Greetings 2 | 3 | on: [pull_request, issues] 4 | 5 | jobs: 6 | greeting: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/first-interaction@v1 10 | with: 11 | repo-token: ${{ secrets.GITHUB_TOKEN }} 12 | issue-message: 'Thanks for raising the issue, a dev will look into this and address this asap' 13 | pr-message: 'Congratulations on your first PR! 😃 😄 😀 ' 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist 3 | stats.json 4 | .DS_Store -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "stable" 4 | cache: 5 | directories: 6 | - node_modules 7 | script: 8 | - npm run lint 9 | - npm test 10 | - npm run build 11 | deploy: 12 | provider: pages 13 | skip_cleanup: true 14 | github_token: $GITHUB_TOKEN 15 | local_dir: dist 16 | on: 17 | branch: master 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # devceldoret-frontend 2 | This repo serves as the website for the Developer Circles Eldoret Community. 3 | 4 | ## Getting started 5 | 1. Fork the project by clicking the fork button above 6 | 2. Clone the project by opening your terminal and running: 7 | 8 | ```shell 9 | git clone https://https://github.com/DevCEldoret/devceldoret-frontend.git 10 | ``` 11 | 12 | 3. `cd` into the newly created directory then run 13 | ```shell 14 | npm install 15 | ``` 16 | 4. Finally, run: 17 | ```shell 18 | npm start --open 19 | ``` 20 | -------------------------------------------------------------------------------- /__mocks__/fileMock.js: -------------------------------------------------------------------------------- 1 | module.exports = ""; 2 | -------------------------------------------------------------------------------- /assets/img/diversity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevCEldoret/devceldoret-frontend/4865641f7c09b4cfa12cf5a2bb006825774054cc/assets/img/diversity.png -------------------------------------------------------------------------------- /assets/img/icons8-facebook 1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevCEldoret/devceldoret-frontend/4865641f7c09b4cfa12cf5a2bb006825774054cc/assets/img/icons8-facebook 1.png -------------------------------------------------------------------------------- /assets/img/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevCEldoret/devceldoret-frontend/4865641f7c09b4cfa12cf5a2bb006825774054cc/assets/img/logo.png -------------------------------------------------------------------------------- /jest.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "transform": { 3 | "^.+\\.tsx?$": "babel-jest" 4 | }, 5 | "moduleNameMapper": { 6 | "\\.(css)$": "identity-obj-proxy", 7 | "\\.(jpg|ico|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$": "/__mocks__/fileMock.js" 8 | }, 9 | "coverageThreshold": { 10 | "global": { 11 | "statements": 80, 12 | "branches": 80, 13 | "functions": 80, 14 | "lines": 80 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "devc-eldoret-frontend", 3 | "version": "1.0.0", 4 | "description": "Developer Circles Eldoret Website", 5 | "main": "index.js", 6 | "scripts": { 7 | "start": "webpack-dev-server --mode development", 8 | "predeploy": "npm run build", 9 | "deploy": "gh-pages -d dist", 10 | "build": "webpack --mode production", 11 | "lint": "eslint src --ext tsx", 12 | "test": "jest --config jest.config.json", 13 | "bundle-report": "webpack --prod --profile --json > stats.json && webpack-bundle-analyzer stats.json" 14 | }, 15 | "husky": { 16 | "hooks": { 17 | "pre-commit": "pretty-quick --staged && npm run lint && npm test" 18 | } 19 | }, 20 | "dependencies": { 21 | "react": "^16.12.0", 22 | "react-bootstrap": "^1.3.0", 23 | "react-dom": "^16.13.0", 24 | "react-icons": "^3.8.0", 25 | "react-particles-js": "^2.7.0", 26 | "react-router": "^5.1.2", 27 | "react-router-dom": "^5.1.2" 28 | }, 29 | "peerDependencies": {}, 30 | "devDependencies": { 31 | "@babel/core": "^7.7.7", 32 | "@babel/plugin-proposal-class-properties": "^7.7.4", 33 | "@babel/preset-env": "^7.7.7", 34 | "@babel/preset-react": "^7.10.4", 35 | "@babel/preset-typescript": "^7.7.7", 36 | "@testing-library/react": "^9.3.0", 37 | "@types/jest": "^24.0.25", 38 | "@types/react": "^16.9.17", 39 | "@types/react-dom": "^16.9.4", 40 | "@types/react-router-dom": "^5.1.5", 41 | "babel-eslint": "^10.0.3", 42 | "babel-jest": "^24.9.0", 43 | "babel-loader": "^8.0.6", 44 | "clean-webpack-plugin": "^3.0.0", 45 | "css-loader": "^3.4.0", 46 | "eslint": "^6.8.0", 47 | "eslint-config-prettier": "^6.11.0", 48 | "eslint-config-ts-react-important-stuff": "^3.0.0", 49 | "eslint-plugin-prettier": "^3.1.1", 50 | "file-loader": "^5.0.2", 51 | "gh-pages": "^2.1.1", 52 | "html-webpack-plugin": "^3.2.0", 53 | "husky": "^3.1.0", 54 | "identity-obj-proxy": "^3.0.0", 55 | "jest": "^24.9.0", 56 | "jest-cli": "^24.9.0", 57 | "prettier": "^1.19.1", 58 | "pretty-quick": "^2.0.1", 59 | "style-loader": "^1.2.1", 60 | "typescript": "^3.7.4", 61 | "webpack": "^4.44.1", 62 | "webpack-bundle-analyzer": "^3.5.2", 63 | "webpack-cli": "^3.3.10", 64 | "webpack-dev-server": "^3.10.1" 65 | }, 66 | "author": "Developer Circles Community", 67 | "license": "ISC", 68 | "homepage": "https://devceldoret.github.io/" 69 | } 70 | -------------------------------------------------------------------------------- /src/.eslintignore: -------------------------------------------------------------------------------- 1 | declarations.d.tsx -------------------------------------------------------------------------------- /src/declarations.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.png"; 2 | declare module "*.css"; 3 | -------------------------------------------------------------------------------- /src/events/events.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevCEldoret/devceldoret-frontend/4865641f7c09b4cfa12cf5a2bb006825774054cc/src/events/events.component.css -------------------------------------------------------------------------------- /src/events/events.component.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { getUpcomingEvents } from "./events.resource"; 3 | import styles from "./events.component.css"; 4 | import { Link } from "react-router-dom"; 5 | import Section from "../hocs/section.component"; 6 | 7 | export default function Events() { 8 | const [events, setEvents] = React.useState([]); 9 | React.useEffect(() => { 10 | getUpcomingEvents().then(events => { 11 | setEvents(events); 12 | }); 13 | }, []); 14 | return ( 15 |
16 |
17 | {events.map(event => ( 18 |
19 |
20 |
21 |

{event.title}

22 |
23 | {event.venue_name},{event.address} 24 |
25 |
26 | From: {event.event_start} To: {event.event_end} 27 |
28 |

{event.description}

29 | 34 |
35 |
36 |
37 | ))} 38 |
39 |
40 | ); 41 | } 42 | -------------------------------------------------------------------------------- /src/events/events.resource.tsx: -------------------------------------------------------------------------------- 1 | export function getUpcomingEvents(): Promise { 2 | return new Promise((resolve, reject) => { 3 | resolve([ 4 | { 5 | id: 0, 6 | title: "Event 1", 7 | description: "Will be about getting people together", 8 | event_start: "23/01/2019", 9 | event_end: "25/01/2019", 10 | belongs_to_hubs: [null], 11 | venue_name: "Sirikwa Hotel", 12 | address: "Oloo Street", 13 | city: "Eldoret", 14 | state: "Uasin Gishu", 15 | zip_code: "string", 16 | country: "Kenya", 17 | created_at: "string", 18 | fq_url: "string", 19 | paid_for_domain: true, 20 | domain: "string", 21 | custom_domain: "string", 22 | event_type: "string", 23 | splash_theme: {}, 24 | ticket_types: [null], 25 | group_ids: [0] 26 | }, 27 | { 28 | id: 0, 29 | title: "Event 1", 30 | description: "Will be about getting people together", 31 | event_start: "23/01/2019", 32 | event_end: "25/01/2019", 33 | belongs_to_hubs: [null], 34 | venue_name: "Sirikwa Hotel", 35 | address: "Oloo Street", 36 | city: "Eldoret", 37 | state: "Uasin Gishu", 38 | zip_code: "string", 39 | country: "Kenya", 40 | created_at: "string", 41 | fq_url: "string", 42 | paid_for_domain: true, 43 | domain: "string", 44 | custom_domain: "string", 45 | event_type: "string", 46 | splash_theme: {}, 47 | ticket_types: [null], 48 | group_ids: [0] 49 | }, 50 | { 51 | id: 0, 52 | title: "Event 1", 53 | description: "Will be about getting people together", 54 | event_start: "23/01/2019", 55 | event_end: "25/01/2019", 56 | belongs_to_hubs: [null], 57 | venue_name: "Sirikwa Hotel", 58 | address: "Oloo Street", 59 | city: "Eldoret", 60 | state: "Uasin Gishu", 61 | zip_code: "string", 62 | country: "Kenya", 63 | created_at: "string", 64 | fq_url: "string", 65 | paid_for_domain: true, 66 | domain: "string", 67 | custom_domain: "string", 68 | event_type: "string", 69 | splash_theme: {}, 70 | ticket_types: [null], 71 | group_ids: [0] 72 | }, 73 | { 74 | id: 0, 75 | title: "Event 1", 76 | description: "Will be about getting people together", 77 | event_start: "23/01/2019", 78 | event_end: "25/01/2019", 79 | belongs_to_hubs: [null], 80 | venue_name: "Sirikwa Hotel", 81 | address: "Oloo Street", 82 | city: "Eldoret", 83 | state: "Uasin Gishu", 84 | zip_code: "string", 85 | country: "Kenya", 86 | created_at: "string", 87 | fq_url: "string", 88 | paid_for_domain: true, 89 | domain: "string", 90 | custom_domain: "string", 91 | event_type: "string", 92 | splash_theme: {}, 93 | ticket_types: [null], 94 | group_ids: [0] 95 | } 96 | ]); 97 | }); 98 | } 99 | -------------------------------------------------------------------------------- /src/hocs/section.component.css: -------------------------------------------------------------------------------- 1 | .sectionTitle { 2 | margin: 2rem 0 !important; 3 | } 4 | 5 | .section { 6 | border-bottom: 1px solid lightgrey; 7 | min-height: 500px; 8 | } 9 | -------------------------------------------------------------------------------- /src/hocs/section.component.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styles from "./section.component.css"; 3 | 4 | export default function Section(props: SectionProps) { 5 | return ( 6 |
7 |
8 |

{props.title}

9 |
10 | {props.children} 11 |
12 | ); 13 | } 14 | 15 | type SectionProps = { 16 | title: string; 17 | children?: React.ReactNode; 18 | }; 19 | -------------------------------------------------------------------------------- /src/home/banner.component.css: -------------------------------------------------------------------------------- 1 | .banner { 2 | position: relative; 3 | display: flex; 4 | align-items: center; 5 | flex-direction: column; 6 | border-radius: 0 0 0 90px; 7 | background: linear-gradient(96.42deg, #3b5998 -41.04%, #00f2ff 102.98%); 8 | } 9 | 10 | .bannerBtn { 11 | margin: 3rem 0; 12 | display: flex; 13 | align-items: flex-end; 14 | } 15 | 16 | .welcomeText { 17 | margin-top: 4.5rem; 18 | margin-bottom: 0; 19 | font-size: 2rem; 20 | text-transform: capitalize; 21 | color: #ffffff; 22 | } 23 | 24 | .welcomeDescription { 25 | font-size: 20px; 26 | margin: 2rem 2rem 0 0; 27 | } 28 | 29 | .bannerImg { 30 | align-self: flex-start; 31 | position: absolute; 32 | } 33 | 34 | @media screen and (min-width: 720px) { 35 | .banner { 36 | height: 33rem; 37 | } 38 | .bannerImg { 39 | bottom: -0.5rem; 40 | } 41 | } 42 | 43 | @media screen and (max-width: 719px) { 44 | .banner { 45 | height: 39rem; 46 | border-radius: 0 0 0 60px; 47 | } 48 | .bannerImg { 49 | bottom: -0.15rem; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/home/banner.component.spec.tsx: -------------------------------------------------------------------------------- 1 | import { render, fireEvent } from "@testing-library/react"; 2 | import Banner from "./banner.component"; 3 | import React from "react"; 4 | 5 | describe("", () => { 6 | test("Renders successfully", () => { 7 | const wrapper = render(); 8 | expect(wrapper.getByText("Welcome to Developer Circles Eldoret")).not.toBe( 9 | null 10 | ); 11 | expect( 12 | wrapper.getByText( 13 | "We are community-driven program based in Eldoret sponsored by Facebook free to join and open to any developer." 14 | ) 15 | ).not.toBe(null); 16 | expect(wrapper.getByAltText("Diversity icon")).not.toBe(null); 17 | expect(wrapper.getByText("Join our Facebook Group")).not.toBe(null); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /src/home/banner.component.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styles from "./banner.component.css"; 3 | import bannerImg from "../../assets/img/diversity.png"; 4 | import fbLogo from "../../assets/img/icons8-facebook 1.png"; 5 | 6 | export default function Banner() { 7 | function goToFbGroup() { 8 | window.open("https://facebook.com/groups/devceldoret", "_blank"); 9 | return null; 10 | } 11 | return ( 12 |
13 |

14 | Welcome to Developer Circles Eldoret 15 |

16 |

17 | We are community-driven program based in Eldoret sponsored by Facebook 18 | free to join and open to any developer. 19 |

20 |
21 | 28 |
29 | Diversity icon 34 |
35 | ); 36 | } 37 | -------------------------------------------------------------------------------- /src/home/home.component.css: -------------------------------------------------------------------------------- 1 | .curveBorderTop { 2 | border-top: 1px dashed transparent; 3 | border-top-right-radius: 90px; 4 | background-color: #fff; 5 | position: absolute; 6 | } 7 | -------------------------------------------------------------------------------- /src/home/home.component.spec.tsx: -------------------------------------------------------------------------------- 1 | import { render } from "@testing-library/react"; 2 | import Home from "./home.component"; 3 | import React from "react"; 4 | 5 | describe("", () => { 6 | test("Renders successfully", () => { 7 | render(); 8 | }); 9 | }); 10 | -------------------------------------------------------------------------------- /src/home/home.component.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styles from "./home.component.css"; 3 | import Events from "../events/events.component"; 4 | import Opportunities from "../opportunities/opportunities.component"; 5 | import bannerImg from "../../assets/img/diversity.png"; 6 | import fbLogo from "../../assets/img/icons8-facebook 1.png"; 7 | import Banner from "./banner.component"; 8 | 9 | export default function HomeComponent() { 10 | return ( 11 |
12 | 13 |
14 |
15 |
16 |
17 | ); 18 | } 19 | -------------------------------------------------------------------------------- /src/index.css: -------------------------------------------------------------------------------- 1 | @import url("https://fonts.googleapis.com/css?family=Poppins"); 2 | @import url("https://stackpath.bootstrapcdn.com/bootswatch/4.3.1/litera/bootstrap.min.css"); 3 | html, 4 | body { 5 | margin: 0; 6 | padding: 0; 7 | box-sizing: border-box; 8 | font-family: "Poppins", sans-serif; 9 | } 10 | 11 | :root { 12 | --primary-color: #3b5998; 13 | --secondary-color: #00f2ff; 14 | } 15 | 16 | h1, 17 | h2, 18 | h3, 19 | h4, 20 | h5, 21 | h6, 22 | p { 23 | font-family: "Poppins"; 24 | } 25 | 26 | button.btn-lg { 27 | font-size: 1.2rem; 28 | } 29 | 30 | button.btn-primary, 31 | a.btn-primary { 32 | background-color: var(--primary-color); 33 | border-radius: 2.5rem; 34 | box-shadow: 0px 4px 4px rgba(0, 0, 0, 0.25); 35 | font-family: "Poppins"; 36 | transition: 0.5s background-color ease-in; 37 | } 38 | 39 | .navbar-light .navbar-nav .nav-link { 40 | color: #000; 41 | } 42 | -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Developer Circles Eldoret 7 | 12 | 17 | 18 | 19 | 20 |
21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/index.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import ReactDOM from "react-dom"; 3 | import { routes } from "./utils/routing"; 4 | import "./index.css"; 5 | 6 | ReactDOM.render(routes, document.getElementById("app")); 7 | -------------------------------------------------------------------------------- /src/navbar/navbar-links.ts: -------------------------------------------------------------------------------- 1 | export const navbarLinks: NavBarLinks[] = [ 2 | { 3 | name: "Home", 4 | url: "/" 5 | }, 6 | { 7 | name: "Events", 8 | url: "/events" 9 | }, 10 | { 11 | name: "University", 12 | url: "/university" 13 | }, 14 | { 15 | name: "Opportunities", 16 | url: "/opportunities" 17 | }, 18 | { 19 | name: "Blog", 20 | url: "/blog" 21 | } 22 | ]; 23 | 24 | type NavBarLinks = { 25 | name: string; 26 | url: string; 27 | }; 28 | -------------------------------------------------------------------------------- /src/navbar/navbar.component.css: -------------------------------------------------------------------------------- 1 | @media screen and (max-width: 720px) { 2 | .logo { 3 | width: 250px; 4 | } 5 | } 6 | @media screen and (min-width: 721px) { 7 | .logo { 8 | width: 350px; 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /src/navbar/navbar.component.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import logo from "../../assets/img/logo.png"; 3 | import { navbarLinks } from "./navbar-links"; 4 | import { Link } from "react-router-dom"; 5 | import styles from "./navbar.component.css"; 6 | export default function Navigation() { 7 | return ( 8 | 49 | ); 50 | } 51 | -------------------------------------------------------------------------------- /src/opportunities/opportunities.component.css: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/DevCEldoret/devceldoret-frontend/4865641f7c09b4cfa12cf5a2bb006825774054cc/src/opportunities/opportunities.component.css -------------------------------------------------------------------------------- /src/opportunities/opportunities.component.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import styles from "./opportunities.component.css"; 3 | import { Link } from "react-router-dom"; 4 | import Section from "../hocs/section.component"; 5 | 6 | export default function Opportunities() { 7 | const [opportunities, setOpportunities] = React.useState([]); 8 | React.useEffect(() => {}, []); 9 | return ( 10 |
11 |
12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 |
PositionCompanyLocationDetails
1MarkOtto@mdo
2JacobThornton@fat
3Larrythe Bird@twitter
42 |
43 |
44 | ); 45 | } 46 | -------------------------------------------------------------------------------- /src/utils/routing.tsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { HashRouter as Router, Route } from "react-router-dom"; 3 | import Home from "../home/home.component"; 4 | import Navbar from "../navbar/navbar.component"; 5 | 6 | export const routes = ( 7 | 8 | 9 | 10 | 11 | ); 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "esModuleInterop": true, 4 | "module": "esnext", 5 | "allowSyntheticDefaultImports": true, 6 | "jsx": "react", 7 | "moduleResolution": "node", 8 | "lib": [ 9 | "dom", 10 | "es5", 11 | "scripthost", 12 | "es2015", 13 | "es2015.promise", 14 | "es2016.array.include", 15 | "es2018" 16 | ], 17 | "noEmit": true, 18 | "target": "esnext" 19 | }, 20 | "include": ["src/**/*"] 21 | } 22 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const path = require("path"); 2 | const HtmlWebpackPlugin = require("html-webpack-plugin"); 3 | const { CleanWebpackPlugin } = require("clean-webpack-plugin"); 4 | 5 | module.exports = { 6 | entry: "./src/index.tsx", 7 | devtool: "source-map", 8 | 9 | output: { 10 | path: path.join(__dirname, "/dist"), 11 | filename: "index.js" 12 | }, 13 | resolve: { 14 | extensions: [".ts", ".tsx", ".jsx", ".js"] 15 | }, 16 | module: { 17 | rules: [ 18 | { 19 | test: /\.m?(js|ts|tsx)$/, 20 | exclude: /node_modules/, 21 | use: { 22 | loader: "babel-loader" 23 | } 24 | }, 25 | { 26 | test: /\.css$/i, 27 | oneOf: [ 28 | { 29 | test: /\.component\.css$/, 30 | use: [ 31 | "style-loader", 32 | { 33 | loader: "css-loader", 34 | options: { 35 | importLoaders: 1, 36 | modules: { 37 | localIdentName: "[name]__[local]___[hash:base64:5]" 38 | } 39 | } 40 | } 41 | ] 42 | }, 43 | { 44 | use: ["style-loader", "css-loader"] 45 | } 46 | ] 47 | }, 48 | { 49 | test: /\.(png|jpe?g|gif)$/i, 50 | use: [ 51 | { 52 | loader: "file-loader" 53 | } 54 | ] 55 | } 56 | ] 57 | }, 58 | plugins: [ 59 | new CleanWebpackPlugin(), 60 | new HtmlWebpackPlugin({ 61 | template: "./src/index.html" 62 | }) 63 | ] 64 | }; 65 | --------------------------------------------------------------------------------