├── src ├── js │ └── main.js ├── components │ └── welcome │ │ ├── index.js │ │ ├── welcome-css.json │ │ ├── welcome.pug │ │ └── welcome.scss ├── styles │ ├── core.scss │ ├── palettes.scss │ ├── variables.scss │ └── reset.scss ├── favicon.ico ├── images │ └── logo.png ├── app.js ├── app.scss └── index.pug ├── .gitattributes ├── .gitignore ├── .travis.yml ├── .editorconfig ├── app.config.json ├── .github └── dependabot.yml ├── .eslintrc.js ├── postcss.config.js ├── license ├── sass-lint.json ├── package.json ├── readme.md └── webpack.config.js /src/js/main.js: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | *.js text eol=lf 2 | -------------------------------------------------------------------------------- /src/components/welcome/index.js: -------------------------------------------------------------------------------- 1 | import './welcome.scss'; 2 | -------------------------------------------------------------------------------- /src/styles/core.scss: -------------------------------------------------------------------------------- 1 | @import 'variables'; 2 | @import 'palettes'; -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | node_modules 3 | package-lock.json 4 | .DS_Store 5 | .vscode/settings.json 6 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipefialho/kratos-boilerplate/HEAD/src/favicon.ico -------------------------------------------------------------------------------- /src/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/felipefialho/kratos-boilerplate/HEAD/src/images/logo.png -------------------------------------------------------------------------------- /src/components/welcome/welcome-css.json: -------------------------------------------------------------------------------- 1 | {"host":"_host_7ja4p_1","title":"_title_7ja4p_1","description":"_description_7ja4p_1"} -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "7" 4 | before_script: 5 | - npm i 6 | cache: 7 | directories: 8 | - "node_modules" 9 | script: 10 | - npm run deploy 11 | -------------------------------------------------------------------------------- /src/app.js: -------------------------------------------------------------------------------- 1 | import * as offline from 'offline-plugin/runtime'; 2 | import './app.scss'; 3 | import './components/welcome'; 4 | 5 | offline.install({ onUpdateReady: () => offline.applyUpdate() }); 6 | -------------------------------------------------------------------------------- /src/components/welcome/welcome.pug: -------------------------------------------------------------------------------- 1 | - var css = require('./welcome-css.json'); 2 | 3 | section(class=css.host) 4 | h1(class=css.title) Kratos Boilerplate 5 | article(class=css.description) A simple boilerplate for creating a static PWA using Webpack, Pug, PostCSS and CSS Modules 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /app.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Kratos Boilerplate", 3 | "description": "A simple boilerplate for creating a static PWA using Webpack, Pug, Stylus and PostCSS", 4 | "url": "https://github.com/felipefialho/kratos-boilerplate", 5 | "logo": "images/logo.png", 6 | "theme_color": "#333333", 7 | "short_name": "Kratos", 8 | "ga": "x", 9 | "twitter": "@felipefialho_" 10 | } 11 | -------------------------------------------------------------------------------- /src/app.scss: -------------------------------------------------------------------------------- 1 | // ================================================== 2 | // Scaffolding 3 | // ================================================== 4 | 5 | @import 'styles/core'; 6 | @import 'styles/reset'; 7 | 8 | html { 9 | -moz-osx-font-smoothing: auto; 10 | -webkit-font-smoothing: auto; 11 | font-size: 10px; 12 | overflow-x: hidden; 13 | } 14 | 15 | body { 16 | -webkit-overflow-scrolling: touch; 17 | overflow-x: hidden; 18 | } -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: "/" 5 | schedule: 6 | interval: monthly 7 | time: "08:00" 8 | open-pull-requests-limit: 99 9 | ignore: 10 | - dependency-name: node-sass 11 | versions: 12 | - ">= 5.0.a, < 5.1" 13 | - dependency-name: pug-code-gen 14 | versions: 15 | - 2.0.3 16 | - dependency-name: webpack-cli 17 | versions: 18 | - 4.5.0 19 | -------------------------------------------------------------------------------- /src/components/welcome/welcome.scss: -------------------------------------------------------------------------------- 1 | // ------------------------------------------------- 2 | // Welcome 3 | // ------------------------------------------------- 4 | 5 | @import '../../styles/core'; 6 | 7 | .host { 8 | font-family: 'Open Sans'; 9 | margin-left: auto; 10 | margin-right: auto; 11 | max-width: $screen-md; 12 | padding: $space; 13 | text-align: center; 14 | } 15 | 16 | .title { 17 | font-size: 4rem; 18 | margin-bottom: $space; 19 | } 20 | 21 | .description { 22 | font-size: 2rem; 23 | } 24 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | browser: true, 4 | es6: true, 5 | jquery: true 6 | }, 7 | globals: { 8 | "fetch": false, 9 | "window": true, 10 | "document": true 11 | }, 12 | extends: 'eslint:recommended', 13 | parserOptions: { 14 | ecmaVersion: 2015, 15 | sourceType: 'module' 16 | }, 17 | rules: { 18 | indent: ['error', 2], 19 | 'no-unused-vars': [1, { vars: 'local', args: 'none' }], 20 | 'linebreak-style': 'off', 21 | quotes: ['error', 'single'], 22 | semi: ['error', 'always'] 23 | }, 24 | env: { 25 | node: true 26 | } 27 | }; 28 | -------------------------------------------------------------------------------- /src/styles/palettes.scss: -------------------------------------------------------------------------------- 1 | // ================================================== 2 | // Palette 3 | // ================================================== 4 | 5 | $white: #ffffff; 6 | $black: #000000; 7 | 8 | $pallet-gray: ( 9 | 50: #f9f9f9, 10 | 100: #d4d4d5, 11 | 200: #b1aeb3, 12 | 300: #928e94, 13 | 400: #868288, 14 | 500: #777777, 15 | 600: #69666c, 16 | 700: #5b575e, 17 | 800: #3f3c42, 18 | 900: #232323, 19 | contrast: ( 20 | 50: #232323, 21 | 100: #ffffff, 22 | 200: #ffffff, 23 | 300: #ffffff, 24 | 400: #ffffff, 25 | 500: #ffffff, 26 | 600: #ffffff, 27 | 700: #ffffff, 28 | 800: #ffffff, 29 | 900: #ffffff 30 | ) 31 | ); 32 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | 'autoprefixer': {}, 4 | 'rucksack-css': {}, 5 | 'lost': {}, 6 | 'postcss-font-magician': {}, 7 | 'cssnano': {}, 8 | 'postcss-modules': { 9 | getJSON: function(cssFileName, json, outputFileName) { 10 | const fs = require('fs'); 11 | const path = require('path'); 12 | const isComponent = /components/.test(path.dirname(cssFileName)); 13 | 14 | if (isComponent) { 15 | const cssName = path.basename(`${cssFileName}`); 16 | const jsonFileName = path.resolve(`${path.dirname(cssFileName)}/${cssName.split('.')[0]}-css.json`); 17 | fs.writeFileSync(jsonFileName, JSON.stringify(json)); 18 | } 19 | } 20 | } 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /license: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 Felipe Fialho 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /sass-lint.json: -------------------------------------------------------------------------------- 1 | { 2 | "options": { 3 | "merge-default-rules": false 4 | }, 5 | "files": { 6 | "ignore": ["node_modules/**/*.s+(a|c)ss"] 7 | }, 8 | "rules": { 9 | "no-trailing-zero": 2, 10 | "bem-depth": 3, 11 | "brace-style": 2, 12 | "declarations-before-nesting": 2, 13 | "empty-line-between-blocks": 2, 14 | "leading-zero": 0, 15 | "one-declaration-per-line": 2, 16 | "space-after-colon": 2, 17 | "space-between-parens": 2, 18 | "trailing-semicolon": 1, 19 | "zero-unit": 1, 20 | "no-color-keywords": 2, 21 | "no-duplicate-properties": 0, 22 | "space-before-brace": 1, 23 | "extends-before-mixins": 2, 24 | "extends-before-declarations": 2, 25 | "placeholder-in-extend": 2, 26 | "mixins-before-declarations": [ 27 | 2, 28 | { 29 | "exclude": [ 30 | "breakpoint", 31 | "above", 32 | "below", 33 | "between", 34 | "mq" 35 | ] 36 | } 37 | ], 38 | "no-warn": 1, 39 | "no-debug": 1, 40 | "no-ids": 2, 41 | "no-important": 1, 42 | "hex-notation": [ 43 | 2, 44 | { 45 | "style": "lowercase" 46 | } 47 | ], 48 | "indentation": [ 49 | 2, 50 | { 51 | "size": 2 52 | } 53 | ], 54 | "property-sort-order": 2 55 | } 56 | } -------------------------------------------------------------------------------- /src/styles/variables.scss: -------------------------------------------------------------------------------- 1 | // ================================================== 2 | // Variables 3 | // 4 | // 1. Spaces 5 | // 2. Media Queries 6 | // 3. zIndex 7 | // ================================================== 8 | 9 | @import '~rupture-sass/rupture'; 10 | @import 'palettes'; 11 | 12 | // -------------------------------------------------- 13 | // 1. Spaces 14 | // -------------------------------------------------- 15 | 16 | $space-xxs : .4rem; 17 | $space-xs : .8rem; 18 | $space-sm : 1.6rem; 19 | $space : 2.4rem; 20 | $space-md : 3.2rem; 21 | $space-lg : 4.8rem; 22 | $space-xlg : 6.4rem; 23 | $space-xxlg : 9.6rem; 24 | 25 | // -------------------------------------------------- 26 | // 2. Media Queries 27 | // -------------------------------------------------- 28 | 29 | $screen-xs : 360px; // xExtra small screen / phone 30 | $screen-sm : 768px; // Extra small screen / phone 31 | $screen-md : 960px; // Small screen / tablet 32 | $screen-lg : 1280px; // Medium screen / desktop 33 | $screen-xlg : 1920px; // Extra Large screen / wide desktop 34 | 35 | $rupture: map-merge($rupture, 36 | ( 37 | anti-overlap: -1px, 38 | scale: 0 $screen-xs $screen-sm $screen-md $screen-lg, 39 | scale-names: '0' 'xs' 'sm' 'md' 'lg' 'xlg' 40 | ) 41 | ); 42 | 43 | // -------------------------------------------------- 44 | // 3. zIndex 45 | // -------------------------------------------------- 46 | 47 | $zindex-bg : -1; 48 | $zindex-default : 1; 49 | -------------------------------------------------------------------------------- /src/index.pug: -------------------------------------------------------------------------------- 1 | - var data = require('../app.config.json'); 2 | 3 | doctype html 4 | html(lang='en') 5 | head 6 | title #{data.title} - #{data.description} 7 | meta(charset='utf-8') 8 | meta(name='description' content=data.description) 9 | meta(name='image' content=data.url + data.logo) 10 | meta(itemprop='name' content=data.title) 11 | meta(itemprop='description' content=data.description) 12 | meta(itemprop='image' content=data.url + data.logo) 13 | meta(name='twitter:card' content='summary') 14 | meta(name='twitter:title' content=data.title) 15 | meta(name='twitter:description' content=data.description) 16 | meta(name='twitter:site' content=data.twitter) 17 | meta(name='twitter:creator' content=data.twitter) 18 | meta(name='twitter:image:src' content=data.url + data.logo) 19 | meta(name='og:title' content=data.title) 20 | meta(name='og:description' content=data.description) 21 | meta(name='og:image' content=data.url + data.logo) 22 | meta(name='og:url' content=data.url) 23 | meta(name='og:site_name' content=data.title) 24 | meta(name='og:locale' content='en') 25 | meta(name='og:type' content='website') 26 | meta(http-equiv='X-UA-Compatible' content='IE=edge') 27 | meta(name='viewport' content='width=device-width, initial-scale=1, maximum-scale=5') 28 | meta(name='theme-color' content=data.theme_color) 29 | link(rel='shortcut icon' type='image/favicon' href='favicon.ico') 30 | script(async src='https://www.googletagmanager.com/gtag/js?id=' + data.ga) 31 | script. 32 | window.dataLayer = window.dataLayer || []; 33 | function gtag(){dataLayer.push(arguments);} 34 | gtag('js', new Date()); 35 | gtag('config', '#{data.ga}'); 36 | body 37 | include components/welcome/welcome 38 | -------------------------------------------------------------------------------- /src/styles/reset.scss: -------------------------------------------------------------------------------- 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 | &:after, &:before { 10 | box-sizing: border-box; 11 | } 12 | } 13 | 14 | html, body, div, span, applet, object, iframe, 15 | h1, h2, h3, h4, h5, h6, p, blockquote, pre, 16 | a, abbr, acronym, address, big, cite, code, 17 | del, dfn, em, img, ins, kbd, q, s, samp, 18 | small, strike, strong, sub, sup, tt, var, 19 | b, u, i, center, 20 | dl, dt, dd, ol, ul, li, 21 | fieldset, form, label, legend, 22 | table, caption, tbody, tfoot, thead, tr, th, td, 23 | article, aside, canvas, details, embed, 24 | figure, figcaption, footer, header, hgroup, 25 | menu, nav, output, ruby, section, summary, 26 | time, mark, audio, video { 27 | border: 0; 28 | font: inherit; 29 | font-size: 100%; 30 | margin: 0; 31 | padding: 0; 32 | vertical-align: baseline; 33 | } 34 | 35 | /* HTML5 display-role reset for older browsers */ 36 | article, aside, details, figcaption, figure, 37 | footer, header, hgroup, menu, nav, section { 38 | display: block; 39 | } 40 | 41 | body { 42 | line-height: 1; 43 | } 44 | 45 | ol, ul { 46 | list-style: none; 47 | } 48 | 49 | blockquote, q { 50 | quotes: none; 51 | } 52 | 53 | blockquote:before, blockquote:after, 54 | q:before, q:after { 55 | content: ''; 56 | content: none; 57 | } 58 | 59 | table { 60 | border-collapse: collapse; 61 | border-spacing: 0; 62 | } 63 | 64 | img, 65 | svg { 66 | max-width: 100%; 67 | vertical-align: top; 68 | } 69 | 70 | button { 71 | background-color: transparent; 72 | border: 0; 73 | padding: 0; 74 | 75 | &:focus { 76 | outline: 0; 77 | } 78 | } 79 | 80 | textarea { 81 | -ms-overflow-style: none; 82 | } 83 | 84 | fieldset { 85 | border: 0; 86 | padding: 0; 87 | } 88 | 89 | input[type="search"]::-webkit-search-decoration, 90 | input[type="search"]::-webkit-search-cancel-button, 91 | input[type="search"]::-webkit-search-results-button, 92 | input[type="search"]::-webkit-search-results-decoration { 93 | -webkit-appearance: none; 94 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "kratos-boilerplate", 3 | "version": "3.1.0", 4 | "title": "Kratos Boilerplate", 5 | "description": "A simple boilerplate for creating a static PWA using Webpack, Pug, PostCSS and CSS Modules", 6 | "homepage": "https://github.com/felipefialho/kratos-boilerplate", 7 | "author": { 8 | "name": "Felipe Fialho", 9 | "email": "hi@felipefialho.com", 10 | "url": "https://www.felipefialho.com" 11 | }, 12 | "browserslist": [ 13 | "> 1%", 14 | "last 2 versions" 15 | ], 16 | "engines": { 17 | "npm": "please-use-yarn", 18 | "yarn": ">= 1.20", 19 | "node": ">= 16.0.0" 20 | }, 21 | "scripts": { 22 | "start": "webpack serve --mode development", 23 | "build": "webpack --mode production", 24 | "deploy": "gh-pages-deploy", 25 | "analyzer": "npm run build && webpack-bundle-analyzer ./dist/stats.json", 26 | "lint": "npm run lint:js && npm run lint:scss", 27 | "lint:scss": "sass-lint -c sass-lint.json 'src/**/*.scss' -v -q", 28 | "lint:js": "eslint ./src/", 29 | "fix:js": "eslint ./src/ --fix" 30 | }, 31 | "gh-pages-deploy": { 32 | "staticpath": "dist", 33 | "prep": [ 34 | "build" 35 | ], 36 | "noprompt": true 37 | }, 38 | "devDependencies": { 39 | "@babel/core": "^7.22.5", 40 | "@babel/preset-env": "^7.22.14", 41 | "autoprefixer": "^10.4.15", 42 | "babel-core": "^6.26.3", 43 | "babel-loader": "^8.3.0", 44 | "babel-preset-env": "^1.7.0", 45 | "clean-webpack-plugin": "^4.0.0", 46 | "copy-webpack-plugin": "^6.4.1", 47 | "css-loader": "^5.2.7", 48 | "cssnano": "^6.0.1", 49 | "eslint": "^8.48.0", 50 | "file-loader": "6.2.0", 51 | "gh-pages-deploy": "^0.5.1", 52 | "html-webpack-plugin": "^4.5.2", 53 | "husky": "^8.0.3", 54 | "imagemin-webpack-plugin": "^2.4.2", 55 | "lost": "^9.0.2", 56 | "mini-css-extract-plugin": "^1.6.2", 57 | "node-sass": "^9.0.0", 58 | "offline-plugin": "^5.0.7", 59 | "postcss": "^8.4.29", 60 | "postcss-font-magician": "^3.0.0", 61 | "postcss-loader": "^4.3.0", 62 | "postcss-modules": "^6.0.0", 63 | "pug": "^3.0.2", 64 | "pug-loader": "^2.4.0", 65 | "rucksack-css": "^1.0.2", 66 | "rupture-sass": "^0.3.0", 67 | "sass": "^1.66.1", 68 | "sass-lint": "^1.13.1", 69 | "sass-loader": "^10.1.1", 70 | "style-loader": "^2.0.0", 71 | "uglifyjs-webpack-plugin": "^2.2.0", 72 | "webpack": "^4.46.0", 73 | "webpack-bundle-analyzer": "^4.9.1", 74 | "webpack-cli": "^4.9.2", 75 | "webpack-dev-server": "^4.15.1", 76 | "webpack-pwa-manifest": "^4.3.0" 77 | }, 78 | "husky": { 79 | "hooks": { 80 | "pre-commit": "npm run lint" 81 | } 82 | }, 83 | "dependencies": {} 84 | } 85 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 |

2 | 3 |

4 | 5 | # Kratos Boilerplate 6 | 7 | > A simple boilerplate for creating a static PWA using Webpack, Pug, PostCSS and CSS Modules 8 | 9 | [![license](https://img.shields.io/github/license/felipefialho/kratos-boilerplate.svg)](./license.md) 10 | [![GitHub contributors](https://img.shields.io/github/contributors/felipefialho/kratos-boilerplate.svg)](https://github.com/felipefialho/kratos-boilerplate/graphs/contributors) 11 | 12 | ## Generate a new project with Yeoman 13 | 14 | To make easy create a new projects, Kratos has a [generator using Yeoman](https://github.com/felipefialho/generator-kratos-boilerplate) 15 | 16 | To use it: 17 | 18 | ```sh 19 | # install yeoman 20 | $ npm install -g yo 21 | 22 | # install kratos generator 23 | $ npm install -g generator-kratos-boilerplate 24 | 25 | # generate a new project 26 | $ yo kratos-boilerplate 27 | ``` 28 | 29 | ## Getting Started 30 | 31 | ```sh 32 | # install dependencies 33 | $ npm i 34 | 35 | # run the project 36 | $ npm start 37 | ``` 38 | 39 | With the commands above, you have everything to start. 40 | 41 | The `app.config.json` file has all minimal config to create your scaffolding. 42 | 43 | ## About CSS 44 | 45 | This project use Sass as CSS preprocessor 😁 46 | 47 | ### Post CSS libs 48 | 49 | For grid system uses [Autoprefixer](https://github.com/postcss/autoprefixer) to make easy use browser prefixes, [Lost](https://github.com/peterramsing/lost) with some help from, [Rucksack](http://simplaio.github.io/rucksack/) for animations, reset and a lot of great mixins, [Rupture](https://github.com/jenius/rupture) for responsive utilities. And [Font Magician](https://github.com/jonathantneal/postcss-font-magician/) to get the webfonts. 50 | 51 | ### CSS Modules 52 | 53 | To make easier create your components and avoid a lot of problems, it boilerplate use [CSS Modules](https://github.com/css-modules/css-modules). 54 | 55 | Example 56 | 57 | ```css 58 | .host text-align center .title font-size 4rem .description font-size 2rem; 59 | ``` 60 | 61 | After the transformation it will become like this 62 | 63 | ```css 64 | ._host_4897k_1 { 65 | text-align: center; 66 | } 67 | 68 | ._title_4897k_9 { 69 | font-size: 4rem; 70 | } 71 | 72 | ._description_4897k_12 { 73 | font-size: 2rem; 74 | } 75 | ``` 76 | 77 | ## Tasks 78 | 79 | - `npm start`: run all tasks and initialize watch for changes and a server 80 | - `npm run build`: run all production tasks create a `dist` folder to deploy 81 | - `npm run lint`: lint javascript and css 82 | - `npm run fix`: command to fix all eslint errors 83 | - `npm run deploy`: run all tasks to build and deploy on gh-pages 84 | 85 | ## License 86 | 87 | MIT License © Felipe Fialho 88 | 89 | [npm-badge]: https://img.shields.io/npm/v/generator-kratos-boilerplate.svg 90 | [npm-url]: https://www.npmjs.com/package/generator-kratos-boilerplate 91 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 2 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 3 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 4 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 5 | const ImageminPlugin = require('imagemin-webpack-plugin').default; 6 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 7 | const OfflinePlugin = require('offline-plugin'); 8 | const path = require('path'); 9 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); 10 | const webpack = require('webpack'); 11 | const WebpackPwaManifest = require('webpack-pwa-manifest'); 12 | 13 | const config = require('./app.config.json'); 14 | 15 | const webapp = { 16 | name: config.title, 17 | short_name: config.short_name, 18 | description: config.description, 19 | background_color: config.theme_color, 20 | theme_color: config.theme_color, 21 | orientation: 'landscape', 22 | icons: [ 23 | { 24 | src: path.resolve('./src/images/logo.png'), 25 | sizes: [96, 128, 192, 256, 384, 512] 26 | } 27 | ] 28 | }; 29 | 30 | const copyFiles = { 31 | patterns: [ 32 | { from: './src/images/', to: './images' }, 33 | { from: './src/favicon.ico', to: './' }, 34 | ], 35 | }; 36 | 37 | const sw = { 38 | safeToUseOptionalCaches: true, 39 | caches: { 40 | main: ['index.html'], 41 | additional: ['*.js?*'] 42 | }, 43 | navigateFallbackURL: '/', 44 | autoUpdate: true, 45 | responseStrategy: 'cache-first', 46 | ServiceWorker: { events: true }, 47 | AppCache: { events: true } 48 | }; 49 | 50 | const baseWebpack = { 51 | entry: { 52 | app: './src/app.js' 53 | }, 54 | output: { 55 | publicPath: '/', 56 | path: path.resolve(__dirname, 'dist'), 57 | filename: '[name].bundle.js' 58 | }, 59 | module: { 60 | rules: [ 61 | { 62 | test: /\.pug/, 63 | loader: 'pug-loader', 64 | }, 65 | { 66 | test: /\.scss/, 67 | use: [ 68 | 'style-loader', 69 | MiniCssExtractPlugin.loader, 70 | { 71 | loader: 'css-loader', 72 | options: { importLoaders: 1 } 73 | }, 74 | 'postcss-loader', 75 | { 76 | loader: 'sass-loader' 77 | } 78 | ] 79 | }, 80 | { 81 | test: /\.jpe?g$|\.gif$|\.png$|\.svg$/, 82 | use: 'file-loader' 83 | }, 84 | { 85 | test: /\.js$/, 86 | exclude: /node_modules/, 87 | use: { 88 | loader: 'babel-loader', 89 | options: { 90 | presets: ['@babel/preset-env'] 91 | } 92 | } 93 | } 94 | ] 95 | }, 96 | plugins: [ 97 | new webpack.DefinePlugin({ 98 | 'process.env.WEBPACK_MODE': JSON.stringify(process.env.WEBPACK_MODE) 99 | }), 100 | new CleanWebpackPlugin({ 101 | cleanAfterEveryBuildPatterns: ['dist'] 102 | }), 103 | new HtmlWebpackPlugin({ 104 | hash: true, 105 | template: './src/index.pug' 106 | }), 107 | new MiniCssExtractPlugin({ 108 | filename: 'style.[contenthash].css', 109 | }), 110 | new CopyWebpackPlugin(copyFiles) 111 | ] 112 | }; 113 | 114 | const prodStart = () => { 115 | baseWebpack.optimization = { 116 | minimizer: [new UglifyJsPlugin()], 117 | }; 118 | baseWebpack.plugins.push(new ImageminPlugin({ test: /\.(jpe?g|png|gif|svg)$/i })); 119 | baseWebpack.plugins.push(new BundleAnalyzerPlugin({ analyzerMode: 'disabled' })); 120 | baseWebpack.plugins.push(new WebpackPwaManifest(webapp)); 121 | baseWebpack.plugins.push(new OfflinePlugin(sw)); 122 | }; 123 | 124 | const devStart = () => { 125 | baseWebpack.devServer = { 126 | contentBase: path.join(__dirname, 'dist'), 127 | compress: true, 128 | open: true, 129 | port: 9000 130 | }; 131 | }; 132 | 133 | module.exports = (env, options) => { 134 | if (options.mode === 'production') { 135 | prodStart(); 136 | } 137 | 138 | if (options.mode === 'development') { 139 | devStart(); 140 | } 141 | 142 | return baseWebpack; 143 | }; 144 | 145 | --------------------------------------------------------------------------------