├── templates ├── .gitkeep ├── base.twig └── index.twig ├── src ├── templates ├── css │ ├── vendor.pcss │ ├── pages │ │ └── homepage.pcss │ ├── components │ │ ├── typography.pcss │ │ ├── webfonts.pcss │ │ └── global.pcss │ └── app.pcss ├── img │ └── favicon-src.png ├── vue │ └── Confetti.vue └── js │ ├── app.js │ └── workbox-catch-handler.js ├── web ├── cpresources │ └── .gitignore ├── .htaccess ├── index.php └── web.config ├── storage └── .gitignore ├── config ├── redactor │ ├── Simple.json │ └── Standard.json ├── db.php ├── routes.php ├── app.php └── general.php ├── README.md ├── craft.bat ├── .gitignore ├── postcss.config.js ├── CHANGELOG.md ├── craft ├── composer.json ├── LICENSE.md ├── .env.example ├── modules └── Module.php ├── webpack.settings.js ├── webpack.common.js ├── package.json ├── webpack.dev.js ├── webpack.prod.js └── tailwind.config.js /templates/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /templates/base.twig: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/templates: -------------------------------------------------------------------------------- 1 | ../templates/ -------------------------------------------------------------------------------- /web/cpresources/.gitignore: -------------------------------------------------------------------------------- 1 | * 2 | !.gitignore 3 | -------------------------------------------------------------------------------- /storage/.gitignore: -------------------------------------------------------------------------------- 1 | backups 2 | logs 3 | runtime 4 | -------------------------------------------------------------------------------- /config/redactor/Simple.json: -------------------------------------------------------------------------------- 1 | { 2 | "buttons": ["bold", "italic"], 3 | "toolbarFixed": true 4 | } 5 | -------------------------------------------------------------------------------- /src/css/vendor.pcss: -------------------------------------------------------------------------------- 1 | /** 2 | * vendor.css 3 | * 4 | * All vendor CSS is imported here. 5 | * 6 | */ 7 | -------------------------------------------------------------------------------- /src/img/favicon-src.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CraftQuest/craft-starter/HEAD/src/img/favicon-src.png -------------------------------------------------------------------------------- /src/css/pages/homepage.pcss: -------------------------------------------------------------------------------- 1 | /** 2 | * pages/homepage.pcss 3 | * 4 | * Styles for the Home page. 5 | * 6 | */ 7 | -------------------------------------------------------------------------------- /src/css/components/typography.pcss: -------------------------------------------------------------------------------- 1 | /** 2 | * components/typography.css 3 | * 4 | * Typography rules. 5 | * 6 | */ 7 | -------------------------------------------------------------------------------- /src/css/components/webfonts.pcss: -------------------------------------------------------------------------------- 1 | /** 2 | * components/webfonts.css 3 | * 4 | * Project webfonts. 5 | * 6 | */ 7 | -------------------------------------------------------------------------------- /src/css/components/global.pcss: -------------------------------------------------------------------------------- 1 | /** 2 | * components/global.css 3 | * 4 | * Project-wide styles 5 | * 6 | */ 7 | 8 | body { 9 | background-color: yellow; 10 | } 11 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CraftQuest Craft Starter Project 2 | 3 | _by Andrew Welch and Ryan Irelan_ 4 | 5 | Created for the livestream at CraftQuest.io: https://craftquest.io/livestreams/creating-a-boilerplate-craft-project 6 | -------------------------------------------------------------------------------- /config/redactor/Standard.json: -------------------------------------------------------------------------------- 1 | { 2 | "buttons": ["formatting", "bold", "italic", "unorderedlist", "orderedlist", "link", "image", "video"], 3 | "plugins": ["fullscreen", "video"], 4 | "linkNewTab": true, 5 | "toolbarFixed": true 6 | } 7 | -------------------------------------------------------------------------------- /web/.htaccess: -------------------------------------------------------------------------------- 1 | 2 | RewriteEngine On 3 | 4 | # Send would-be 404 requests to Craft 5 | RewriteCond %{REQUEST_FILENAME} !-f 6 | RewriteCond %{REQUEST_FILENAME} !-d 7 | RewriteCond %{REQUEST_URI} !^/(favicon\.ico|apple-touch-icon.*\.png)$ [NC] 8 | RewriteRule (.+) index.php?p=$1 [QSA,L] 9 | 10 | -------------------------------------------------------------------------------- /craft.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | rem ------------------------------------------------------------- 4 | rem Craft command line bootstrap script for Windows 5 | rem ------------------------------------------------------------- 6 | 7 | @setlocal 8 | 9 | set CRAFT_PATH=%~dp0 10 | 11 | if "%PHP_COMMAND%" == "" set PHP_COMMAND=php.exe 12 | 13 | "%PHP_COMMAND%" "%CRAFT_PATH%craft" %* 14 | 15 | @endlocal 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.env 2 | /.idea 3 | /vendor 4 | .DS_Store 5 | .cache 6 | .project 7 | .settings 8 | *.esproj 9 | *.sublime-workspace 10 | *.sublime-project 11 | *.tmproj 12 | *.tmproject 13 | .vscode/* 14 | !.vscode/settings.json 15 | !.vscode/tasks.json 16 | !.vscode/launch.json 17 | !.vscode/extensions.json 18 | config.codekit3 19 | prepros-6.config 20 | /node_modules/* 21 | /web/dist/* 22 | /web/cpresources/* 23 | -------------------------------------------------------------------------------- /postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: [ 3 | require('postcss-import'), 4 | require('postcss-extend'), 5 | require('postcss-simple-vars'), 6 | require('postcss-nested-ancestors'), 7 | require('postcss-nested'), 8 | require('postcss-hexrgba'), 9 | require('autoprefixer'), 10 | require('tailwindcss')('./tailwind.config.js') 11 | ] 12 | }; 13 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | ## 1.0.5 - 2021-04-14 4 | ### Changed 5 | - Updated packages to latest. 6 | 7 | ## 1.0.4 - 2020-06-01 8 | ### Changed 9 | - Updated packages to latest. 10 | 11 | ## 1.0.3 - 2018-11-02 12 | ### Changed 13 | - We made a mistake. Added type of project to composer file. 14 | 15 | ## 1.0.2 - 2018-11-02 16 | ### Changed 17 | - Conforming to the highest of high standards of Packagist. I worship you. 18 | 19 | ## 1.0.1 - 2018-11-02 20 | ### Changed 21 | - Added version number, etc. to `composer.json` 22 | 23 | ## 1.0.0 - 2018-11-02 24 | ### Added 25 | - Initial release 26 | -------------------------------------------------------------------------------- /web/index.php: -------------------------------------------------------------------------------- 1 | load(); 16 | } 17 | 18 | // Load and run Craft 19 | define('CRAFT_ENVIRONMENT', getenv('ENVIRONMENT') ?: 'production'); 20 | $app = require CRAFT_VENDOR_PATH.'/craftcms/cms/bootstrap/web.php'; 21 | $app->run(); 22 | -------------------------------------------------------------------------------- /config/db.php: -------------------------------------------------------------------------------- 1 | getenv('DB_DRIVER'), 13 | 'server' => getenv('DB_SERVER'), 14 | 'user' => getenv('DB_USER'), 15 | 'password' => getenv('DB_PASSWORD'), 16 | 'database' => getenv('DB_DATABASE'), 17 | 'schema' => getenv('DB_SCHEMA'), 18 | 'tablePrefix' => getenv('DB_TABLE_PREFIX'), 19 | 'port' => getenv('DB_PORT') 20 | ]; 21 | -------------------------------------------------------------------------------- /craft: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env php 2 | load(); 17 | } 18 | 19 | // Load and run Craft 20 | define('CRAFT_ENVIRONMENT', getenv('ENVIRONMENT') ?: 'production'); 21 | $app = require CRAFT_VENDOR_PATH.'/craftcms/cms/bootstrap/console.php'; 22 | $exitCode = $app->run(); 23 | exit($exitCode); 24 | -------------------------------------------------------------------------------- /src/vue/Confetti.vue: -------------------------------------------------------------------------------- 1 | 5 | 6 | 25 | -------------------------------------------------------------------------------- /src/js/app.js: -------------------------------------------------------------------------------- 1 | import styles from '../css/app.pcss'; 2 | 3 | // App main 4 | const main = async () => { 5 | // Import our CSS 6 | //const Styles = await import(/* webpackChunkName: "styles" */ '../css/app.pcss'); 7 | // Async load the vue module 8 | const Vue = await import(/* webpackChunkName: "vue" */ 'vue'); 9 | // Create our vue instance 10 | const vm = new Vue.default({ 11 | el: "#app", 12 | components: { 13 | 'confetti': () => import(/* webpackChunkName: "confetti" */ '../vue/Confetti.vue'), 14 | }, 15 | data: { 16 | }, 17 | methods: { 18 | }, 19 | mounted() { 20 | }, 21 | }); 22 | }; 23 | // Execute async function 24 | main().then( (value) => { 25 | }); 26 | -------------------------------------------------------------------------------- /config/routes.php: -------------------------------------------------------------------------------- 1 | ' => ['template' => 'blog/_archive'], 15 | * 16 | * That example would match URIs such as `/blog/archive/2012`, and pass the 17 | * request along to the `blog/_archive` template, providing it a `year` variable 18 | * set to the value `2012`. 19 | */ 20 | 21 | return [ 22 | 23 | ]; 24 | -------------------------------------------------------------------------------- /config/app.php: -------------------------------------------------------------------------------- 1 | [ 22 | 'my-module' => \modules\Module::class, 23 | ], 24 | //'bootstrap' => ['my-module'], 25 | ]; 26 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "craftquest/craft-starter", 3 | "description": "A starter Craft installation from livestream with Andrew Welch.", 4 | "version": "1.0.5", 5 | "type": "project", 6 | "require": { 7 | "craftcms/cms": "^3.0.0", 8 | "yiisoft/yii2-redis": "^2.0.6", 9 | "vlucas/phpdotenv": "^2.4.0", 10 | "nystudio107/craft-imageoptimize": "^1.3.2", 11 | "nystudio107/craft-minify": "^1.2.5", 12 | "nystudio107/craft-retour": "^3.0.0", 13 | "nystudio107/craft-seomatic": "^3.0.0", 14 | "nystudio107/craft-typogrify": "^1.1.1", 15 | "nystudio107/craft-twigpack": "^1.0.0", 16 | "ostark/craft-async-queue": "^1.3.0" 17 | }, 18 | "autoload": { 19 | "psr-4": { 20 | "modules\\": "modules/" 21 | } 22 | }, 23 | "config": { 24 | "optimize-autoloader": true, 25 | "platform": { 26 | "php": "7.2.5" 27 | } 28 | }, 29 | "scripts": { 30 | "post-root-package-install": [ 31 | "@php -r \"file_exists('.env') || copy('.env.example', '.env');\"" 32 | ] 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 nystudio107 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 10 | -------------------------------------------------------------------------------- /.env.example: -------------------------------------------------------------------------------- 1 | # The environment Craft is currently running in ('dev', 'staging', 'production', etc.) 2 | ENVIRONMENT="dev" 3 | 4 | # The secure key Craft will use for hashing and encrypting data 5 | SECURITY_KEY="" 6 | 7 | # The database driver that will be used ('mysql' or 'pgsql') 8 | DB_DRIVER="mysql" 9 | 10 | # The database server name or IP address (usually this is 'localhost' or '127.0.0.1') 11 | DB_SERVER="localhost" 12 | 13 | # The database username to connect with 14 | DB_USER="root" 15 | 16 | # The database password to connect with 17 | DB_PASSWORD="" 18 | 19 | # The name of the database to select 20 | DB_DATABASE="" 21 | 22 | # The database schema that will be used (PostgreSQL only) 23 | DB_SCHEMA="public" 24 | 25 | # The prefix that should be added to generated table names (only necessary if multiple things are sharing the same database) 26 | DB_TABLE_PREFIX="" 27 | 28 | # The port to connect to the database with. Will default to 5432 for PostgreSQL and 3306 for MySQL. 29 | DB_PORT="" 30 | 31 | # webpack example settings for Homestead/Vagrant 32 | DEVSERVER_PUBLIC="http://192.168.10.10:8080" 33 | DEVSERVER_HOST="0.0.0.0" 34 | DEVSERVER_POLL=1 35 | DEVSERVER_PORT=8080 36 | DEVSERVER_HTTPS=0 -------------------------------------------------------------------------------- /src/css/app.pcss: -------------------------------------------------------------------------------- 1 | /** 2 | * app.css 3 | * 4 | * The entry point for the css. 5 | * 6 | */ 7 | 8 | /** 9 | * This injects Tailwind's base styles, which is a combination of 10 | * Normalize.css and some additional base styles. 11 | * 12 | * You can see the styles here: 13 | * https://github.com/tailwindcss/tailwindcss/blob/master/css/preflight.css 14 | */ 15 | @import "tailwindcss/preflight"; 16 | 17 | /** 18 | * This injects any component classes registered by plugins. 19 | * 20 | */ 21 | @import 'tailwindcss/components'; 22 | 23 | /** 24 | * Here we add custom component classes; stuff we want loaded 25 | * *before* the utilities so that the utilities can still 26 | * override them. 27 | * 28 | */ 29 | @import './components/global.pcss'; 30 | @import './components/typography.pcss'; 31 | @import './components/webfonts.pcss'; 32 | 33 | /** 34 | * This injects all of Tailwind's utility classes, generated based on your 35 | * config file. 36 | * 37 | */ 38 | @import 'tailwindcss/utilities'; 39 | 40 | /** 41 | * Include styles for individual pages 42 | * 43 | */ 44 | @import './pages/homepage.pcss'; 45 | 46 | /** 47 | * Include vendor css. 48 | * 49 | */ 50 | @import 'vendor.pcss'; 51 | -------------------------------------------------------------------------------- /src/js/workbox-catch-handler.js: -------------------------------------------------------------------------------- 1 | // fallback URLs 2 | const FALLBACK_HTML_URL = '/offline.html'; 3 | const FALLBACK_IMAGE_URL = '/offline.svg'; 4 | 5 | // This "catch" handler is triggered when any of the other routes fail to 6 | // generate a response. 7 | // https://developers.google.com/web/tools/workbox/guides/advanced-recipes#provide_a_fallback_response_to_a_route 8 | workbox.routing.setCatchHandler(({event, request, url}) => { 9 | // Use event, request, and url to figure out how to respond. 10 | // One approach would be to use request.destination, see 11 | // https://medium.com/dev-channel/service-worker-caching-strategies-based-on-request-types-57411dd7652c 12 | switch (request.destination) { 13 | case 'document': 14 | return caches.match(FALLBACK_HTML_URL); 15 | break; 16 | 17 | case 'image': 18 | return caches.match(FALLBACK_IMAGE_URL); 19 | break; 20 | 21 | default: 22 | // If we don't have a fallback, just return an error response. 23 | return Response.error(); 24 | } 25 | }); 26 | 27 | // Use a stale-while-revalidate strategy for all other requests. 28 | workbox.routing.setDefaultHandler( 29 | workbox.strategies.staleWhileRevalidate() 30 | ); 31 | -------------------------------------------------------------------------------- /web/web.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /modules/Module.php: -------------------------------------------------------------------------------- 1 | getModule('my-module')`. 11 | * 12 | * You can change its module ID ("my-module") to something else from 13 | * config/app.php. 14 | * 15 | * If you want the module to get loaded on every request, uncomment this line 16 | * in config/app.php: 17 | * 18 | * 'bootstrap' => ['my-module'] 19 | * 20 | * Learn more about Yii module development in Yii's documentation: 21 | * http://www.yiiframework.com/doc-2.0/guide-structure-modules.html 22 | */ 23 | class Module extends \yii\base\Module 24 | { 25 | /** 26 | * Initializes the module. 27 | */ 28 | public function init() 29 | { 30 | // Set a @modules alias pointed to the modules/ directory 31 | Craft::setAlias('@modules', __DIR__); 32 | 33 | // Set the controllerNamespace based on whether this is a console or web request 34 | if (Craft::$app->getRequest()->getIsConsoleRequest()) { 35 | $this->controllerNamespace = 'modules\\console\\controllers'; 36 | } else { 37 | $this->controllerNamespace = 'modules\\controllers'; 38 | } 39 | 40 | parent::init(); 41 | 42 | // Custom initialization code goes here... 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /config/general.php: -------------------------------------------------------------------------------- 1 | [ 14 | // Default Week Start Day (0 = Sunday, 1 = Monday...) 15 | 'defaultWeekStartDay' => 0, 16 | 17 | // Enable CSRF Protection (recommended) 18 | 'enableCsrfProtection' => true, 19 | 20 | // Whether generated URLs should omit "index.php" 21 | 'omitScriptNameInUrls' => true, 22 | 23 | // Control Panel trigger word 24 | 'cpTrigger' => 'admin', 25 | 26 | // The secure key Craft will use for hashing and encrypting data 27 | 'securityKey' => getenv('SECURITY_KEY'), 28 | ], 29 | 30 | // Dev environment settings 31 | 'dev' => [ 32 | // Base site URL 33 | 'siteUrl' => null, 34 | 35 | // Dev Mode (see https://craftcms.com/support/dev-mode) 36 | 'devMode' => true, 37 | ], 38 | 39 | // Staging environment settings 40 | 'staging' => [ 41 | // Base site URL 42 | 'siteUrl' => null, 43 | ], 44 | 45 | // Production environment settings 46 | 'production' => [ 47 | // Base site URL 48 | 'siteUrl' => null, 49 | ], 50 | ]; 51 | -------------------------------------------------------------------------------- /webpack.settings.js: -------------------------------------------------------------------------------- 1 | // webpack.settings.js - webpack settings config 2 | 3 | // node modules 4 | require('dotenv').config(); 5 | 6 | // Webpack settings exports 7 | // noinspection WebpackConfigHighlighting 8 | module.exports = { 9 | name: "Example Project", 10 | copyright: "Example Company, Inc.", 11 | paths: { 12 | src: { 13 | base: "./src/", 14 | css: "./src/css/", 15 | js: "./src/js/" 16 | }, 17 | dist: { 18 | base: "./web/dist/", 19 | clean: [ 20 | "./img", 21 | "./criticalcss", 22 | "./css", 23 | "./js" 24 | ] 25 | }, 26 | templates: "./templates/" 27 | }, 28 | urls: { 29 | live: "https://example.com/", 30 | local: "http://example.test/", 31 | critical: "http://example.test/", 32 | publicPath: "/dist/" 33 | }, 34 | vars: { 35 | cssName: "styles" 36 | }, 37 | entries: { 38 | "app": "app.js" 39 | }, 40 | copyWebpackConfig: [ 41 | { 42 | from: "./src/js/workbox-catch-handler.js", 43 | to: "js/[name].[ext]" 44 | } 45 | ], 46 | criticalCssConfig: { 47 | base: "./web/dist/criticalcss/", 48 | suffix: "_critical.min.css", 49 | criticalHeight: 1200, 50 | criticalWidth: 1200, 51 | ampPrefix: "amp_", 52 | ampCriticalHeight: 19200, 53 | ampCriticalWidth: 600, 54 | pages: [ 55 | { 56 | url: "", 57 | template: "index" 58 | } 59 | ] 60 | }, 61 | devServerConfig: { 62 | public: () => process.env.DEVSERVER_PUBLIC || "http://localhost:8080", 63 | host: () => process.env.DEVSERVER_HOST || "localhost", 64 | poll: () => process.env.DEVSERVER_POLL || false, 65 | port: () => process.env.DEVSERVER_PORT || 8080, 66 | https: () => process.env.DEVSERVER_HTTPS || false, 67 | }, 68 | manifestConfig: { 69 | basePath: "" 70 | }, 71 | purgeCssConfig: { 72 | paths: [ 73 | "./templates/**/*.{twig,html}", 74 | "./src/vue/**/*.{vue,html}" 75 | ], 76 | whitelist: [ 77 | "./src/css/components/**/*.{css,pcss}" 78 | ], 79 | whitelistPatterns: [], 80 | extensions: [ 81 | "html", 82 | "js", 83 | "twig", 84 | "vue" 85 | ] 86 | }, 87 | saveRemoteFileConfig: [ 88 | { 89 | url: "https://www.google-analytics.com/analytics.js", 90 | filepath: "js/analytics.js" 91 | } 92 | ], 93 | createSymlinkConfig: [ 94 | { 95 | origin: "img/favicons/favicon.ico", 96 | symlink: "../favicon.ico" 97 | } 98 | ], 99 | webappConfig: { 100 | logo: "./src/img/favicon-src.png", 101 | prefix: "img/favicons/" 102 | }, 103 | workboxConfig: { 104 | swDest: "../sw.js", 105 | precacheManifestFilename: "js/precache-manifest.[manifestHash].js", 106 | importScripts: [ 107 | "/dist/workbox-catch-handler.js" 108 | ], 109 | exclude: [ 110 | /\.(png|jpe?g|gif|svg|webp)$/i, 111 | /\.map$/, 112 | /^manifest.*\\.js(?:on)?$/, 113 | ], 114 | globDirectory: "./web/", 115 | globPatterns: [ 116 | "offline.html", 117 | "offline.svg" 118 | ], 119 | offlineGoogleAnalytics: true, 120 | runtimeCaching: [ 121 | { 122 | urlPattern: /\.(?:png|jpg|jpeg|svg|webp)$/, 123 | handler: "cacheFirst", 124 | options: { 125 | cacheName: "images", 126 | expiration: { 127 | maxEntries: 20 128 | } 129 | } 130 | } 131 | ] 132 | } 133 | }; 134 | -------------------------------------------------------------------------------- /webpack.common.js: -------------------------------------------------------------------------------- 1 | // webpack.common.js - common webpack config 2 | const LEGACY_CONFIG = 'legacy'; 3 | const MODERN_CONFIG = 'modern'; 4 | 5 | // node modules 6 | const path = require('path'); 7 | const merge = require('webpack-merge'); 8 | 9 | // webpack plugins 10 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 11 | const ManifestPlugin = require('webpack-manifest-plugin'); 12 | const VueLoaderPlugin = require('vue-loader/lib/plugin'); 13 | const WebpackNotifierPlugin = require('webpack-notifier'); 14 | 15 | // config files 16 | const pkg = require('./package.json'); 17 | const settings = require('./webpack.settings.js'); 18 | 19 | // Configure Babel loader 20 | const configureBabelLoader = (browserList) => { 21 | return { 22 | test: /\.js$/, 23 | exclude: /node_modules/, 24 | use: { 25 | loader: 'babel-loader', 26 | options: { 27 | presets: [ 28 | [ 29 | '@babel/preset-env', { 30 | modules: false, 31 | useBuiltIns: 'entry', 32 | targets: { 33 | browsers: browserList, 34 | }, 35 | } 36 | ], 37 | ], 38 | plugins: [ 39 | '@babel/plugin-syntax-dynamic-import', 40 | [ 41 | "@babel/plugin-transform-runtime", { 42 | "regenerator": true 43 | } 44 | ] 45 | ], 46 | }, 47 | }, 48 | }; 49 | }; 50 | 51 | // Configure Entries 52 | const configureEntries = () => { 53 | let entries = {}; 54 | for (const [key, value] of Object.entries(settings.entries)) { 55 | entries[key] = path.resolve(__dirname, settings.paths.src.js + value); 56 | } 57 | 58 | return entries; 59 | }; 60 | 61 | // Configure Font loader 62 | const configureFontLoader = () => { 63 | return { 64 | test: /\.(ttf|eot|woff2?)$/i, 65 | use: [ 66 | { 67 | loader: 'file-loader', 68 | options: { 69 | name: 'fonts/[name].[ext]' 70 | } 71 | } 72 | ] 73 | }; 74 | }; 75 | 76 | // Configure Manifest 77 | const configureManifest = (fileName) => { 78 | return { 79 | fileName: fileName, 80 | basePath: settings.manifestConfig.basePath, 81 | map: (file) => { 82 | file.name = file.name.replace(/(\.[a-f0-9]{32})(\..*)$/, '$2'); 83 | return file; 84 | }, 85 | }; 86 | }; 87 | 88 | // Configure Vue loader 89 | const configureVueLoader = () => { 90 | return { 91 | test: /\.vue$/, 92 | loader: 'vue-loader' 93 | }; 94 | }; 95 | 96 | // The base webpack config 97 | const baseConfig = { 98 | name: pkg.name, 99 | entry: configureEntries(), 100 | output: { 101 | path: path.resolve(__dirname, settings.paths.dist.base), 102 | publicPath: settings.urls.publicPath 103 | }, 104 | resolve: { 105 | alias: { 106 | 'vue$': 'vue/dist/vue.esm.js' 107 | } 108 | }, 109 | module: { 110 | rules: [ 111 | configureFontLoader(), 112 | configureVueLoader(), 113 | ], 114 | }, 115 | plugins: [ 116 | new WebpackNotifierPlugin({title: 'Webpack', excludeWarnings: true, alwaysNotify: true}), 117 | new VueLoaderPlugin(), 118 | ] 119 | }; 120 | 121 | // Legacy webpack config 122 | const legacyConfig = { 123 | module: { 124 | rules: [ 125 | configureBabelLoader(Object.values(pkg.browserslist.legacyBrowsers)), 126 | ], 127 | }, 128 | plugins: [ 129 | new CopyWebpackPlugin( 130 | settings.copyWebpackConfig 131 | ), 132 | new ManifestPlugin( 133 | configureManifest('manifest-legacy.json') 134 | ), 135 | ] 136 | }; 137 | 138 | // Modern webpack config 139 | const modernConfig = { 140 | module: { 141 | rules: [ 142 | configureBabelLoader(Object.values(pkg.browserslist.modernBrowsers)), 143 | ], 144 | }, 145 | plugins: [ 146 | new ManifestPlugin( 147 | configureManifest('manifest.json') 148 | ), 149 | ] 150 | }; 151 | 152 | // Common module exports 153 | // noinspection WebpackConfigHighlighting 154 | module.exports = { 155 | 'legacyConfig': merge( 156 | legacyConfig, 157 | baseConfig, 158 | ), 159 | 'modernConfig': merge( 160 | modernConfig, 161 | baseConfig, 162 | ), 163 | }; 164 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "example-project", 3 | "version": "1.0.0", 4 | "description": "Example Project brand website", 5 | "keywords": [ 6 | "Example", 7 | "Keywords" 8 | ], 9 | "homepage": "https://github.com/example-developer/example-project", 10 | "bugs": { 11 | "email": "someone@example-developer.com", 12 | "url": "https://github.com/example-developer/example-project/issues" 13 | }, 14 | "license": "SEE LICENSE IN LICENSE.md", 15 | "author": { 16 | "name": "Example Developer", 17 | "email": "someone@example-developer.com", 18 | "url": "https://example-developer.com" 19 | }, 20 | "browser": "/web/index.php", 21 | "repository": { 22 | "type": "git", 23 | "url": "git+https://github.com/example-developer/example-project.git" 24 | }, 25 | "private": true, 26 | "scripts": { 27 | "dev": "webpack-dev-server --config webpack.dev.js", 28 | "build": "webpack --config webpack.prod.js --progress --hide-modules" 29 | }, 30 | "browserslist": { 31 | "production": [ 32 | "> 1%", 33 | "last 2 versions", 34 | "Firefox ESR" 35 | ], 36 | "legacyBrowsers": [ 37 | "> 1%", 38 | "last 2 versions", 39 | "Firefox ESR" 40 | ], 41 | "modernBrowsers": [ 42 | "last 2 Chrome versions", 43 | "not Chrome < 60", 44 | "last 2 Safari versions", 45 | "not Safari < 10.1", 46 | "last 2 iOS versions", 47 | "not iOS < 10.3", 48 | "last 2 Firefox versions", 49 | "not Firefox < 54", 50 | "last 2 Edge versions", 51 | "not Edge < 15" 52 | ] 53 | }, 54 | "devDependencies": { 55 | "@babel/core": "^7.1.0", 56 | "@babel/plugin-syntax-dynamic-import": "^7.0.0", 57 | "@babel/plugin-transform-runtime": "^7.1.0", 58 | "@babel/preset-env": "^7.1.0", 59 | "@babel/register": "^7.0.0", 60 | "@babel/runtime": "^7.0.0", 61 | "autoprefixer": "^9.1.5", 62 | "babel-loader": "^8.0.2", 63 | "clean-webpack-plugin": "^0.1.19", 64 | "copy-webpack-plugin": "^4.5.2", 65 | "create-symlink-webpack-plugin": "^1.0.0", 66 | "critical": "^1.3.4", 67 | "critical-css-webpack-plugin": "^0.2.0", 68 | "css-loader": "^1.0.0", 69 | "cssnano": "^4.1.0", 70 | "dotenv": "^6.1.0", 71 | "file-loader": "^2.0.0", 72 | "git-rev-sync": "^1.12.0", 73 | "glob-all": "^3.1.0", 74 | "html-webpack-plugin": "^3.2.0", 75 | "ignore-loader": "^0.1.2", 76 | "imagemin": "^6.0.0", 77 | "imagemin-gifsicle": "^5.2.0", 78 | "imagemin-mozjpeg": "^7.0.0", 79 | "imagemin-optipng": "^5.2.1", 80 | "imagemin-svgo": "^7.0.0", 81 | "imagemin-webp": "^4.1.0", 82 | "imagemin-webp-webpack-plugin": "^1.0.2", 83 | "img-loader": "^3.0.1", 84 | "mini-css-extract-plugin": "^0.4.3", 85 | "moment": "^2.22.2", 86 | "optimize-css-assets-webpack-plugin": "^5.0.1", 87 | "postcss": "^7.0.2", 88 | "postcss-extend": "^1.0.5", 89 | "postcss-hexrgba": "^1.0.1", 90 | "postcss-import": "^12.0.0", 91 | "postcss-loader": "^3.0.0", 92 | "postcss-nested": "^4.1.0", 93 | "postcss-nested-ancestors": "^2.0.0", 94 | "postcss-simple-vars": "^5.0.1", 95 | "purgecss-webpack-plugin": "^1.3.0", 96 | "purgecss-whitelister": "^2.2.0", 97 | "resolve-url-loader": "^3.0.0", 98 | "sane": "^4.0.1", 99 | "save-remote-file-webpack-plugin": "^1.0.0", 100 | "style-loader": "^0.23.0", 101 | "symlink-webpack-plugin": "^0.0.4", 102 | "terser-webpack-plugin": "^1.1.0", 103 | "vue-loader": "^15.4.2", 104 | "vue-style-loader": "^4.1.2", 105 | "vue-template-compiler": "^2.5.17", 106 | "webapp-webpack-plugin": "https://github.com/brunocodutra/webapp-webpack-plugin.git", 107 | "webpack": "^4.19.1", 108 | "webpack-bundle-analyzer": "^3.0.2", 109 | "webpack-cli": "^3.1.1", 110 | "webpack-dashboard": "^2.0.0", 111 | "webpack-dev-server": "^3.1.9", 112 | "webpack-manifest-plugin": "^2.0.4", 113 | "webpack-merge": "^4.1.4", 114 | "webpack-notifier": "^1.6.0", 115 | "workbox-webpack-plugin": "^3.6.2" 116 | }, 117 | "dependencies": { 118 | "@babel/polyfill": "^7.0.0", 119 | "axios": "^0.18.0", 120 | "tailwindcss": "^0.6.6", 121 | "vue": "^2.5.17", 122 | "vue-confetti": "^0.4.2" 123 | } 124 | } 125 | -------------------------------------------------------------------------------- /webpack.dev.js: -------------------------------------------------------------------------------- 1 | // webpack.dev.js - developmental builds 2 | const LEGACY_CONFIG = 'legacy'; 3 | const MODERN_CONFIG = 'modern'; 4 | 5 | // node modules 6 | const merge = require('webpack-merge'); 7 | const path = require('path'); 8 | const sane = require('sane'); 9 | const webpack = require('webpack'); 10 | 11 | // webpack plugins 12 | const Dashboard = require('webpack-dashboard'); 13 | const DashboardPlugin = require('webpack-dashboard/plugin'); 14 | const dashboard = new Dashboard(); 15 | 16 | // config files 17 | const common = require('./webpack.common.js'); 18 | const pkg = require('./package.json'); 19 | const settings = require('./webpack.settings.js'); 20 | 21 | // Configure the webpack-dev-server 22 | const configureDevServer = (buildType) => { 23 | return { 24 | public: settings.devServerConfig.public(), 25 | contentBase: path.resolve(__dirname, settings.paths.templates), 26 | host: settings.devServerConfig.host(), 27 | port: settings.devServerConfig.port(), 28 | https: !!parseInt(settings.devServerConfig.https()), 29 | quiet: true, 30 | hot: true, 31 | hotOnly: true, 32 | overlay: true, 33 | stats: 'errors-only', 34 | watchOptions: { 35 | poll: !!parseInt(settings.devServerConfig.poll()), 36 | }, 37 | headers: { 38 | 'Access-Control-Allow-Origin': '*' 39 | }, 40 | // Use sane to monitor all of the templates files and sub-directories 41 | before: (app, server) => { 42 | const watcher = sane(path.join(__dirname, settings.paths.templates), { 43 | glob: ['**/*'], 44 | poll: !!parseInt(settings.devServerConfig.poll()), 45 | }); 46 | watcher.on('change', function(filePath, root, stat) { 47 | console.log(' File modified:', filePath); 48 | server.sockWrite(server.sockets, "content-changed"); 49 | }); 50 | }, 51 | }; 52 | }; 53 | 54 | // Configure Image loader 55 | const configureImageLoader = (buildType) => { 56 | if (buildType === LEGACY_CONFIG) { 57 | return { 58 | test: /\.(png|jpe?g|gif|svg|webp)$/i, 59 | use: [ 60 | { 61 | loader: 'file-loader', 62 | options: { 63 | name: 'img/[name].[hash].[ext]' 64 | } 65 | } 66 | ] 67 | }; 68 | } 69 | if (buildType === MODERN_CONFIG) { 70 | return { 71 | test: /\.(png|jpe?g|gif|svg|webp)$/i, 72 | use: [ 73 | { 74 | loader: 'file-loader', 75 | options: { 76 | name: 'img/[name].[hash].[ext]' 77 | } 78 | } 79 | ] 80 | }; 81 | } 82 | }; 83 | 84 | // Configure the Postcss loader 85 | const configurePostcssLoader = (buildType) => { 86 | // Don't generate CSS for the legacy config in development 87 | if (buildType === LEGACY_CONFIG) { 88 | return { 89 | test: /\.(pcss|css)$/, 90 | loader: 'ignore-loader' 91 | }; 92 | } 93 | if (buildType === MODERN_CONFIG) { 94 | return { 95 | test: /\.(pcss|css)$/, 96 | use: [ 97 | { 98 | loader: 'style-loader', 99 | }, 100 | { 101 | loader: 'vue-style-loader', 102 | }, 103 | { 104 | loader: 'css-loader', 105 | options: { 106 | importLoaders: 2, 107 | sourceMap: true 108 | } 109 | }, 110 | { 111 | loader: 'resolve-url-loader' 112 | }, 113 | { 114 | loader: 'postcss-loader', 115 | options: { 116 | sourceMap: true 117 | } 118 | } 119 | ] 120 | }; 121 | } 122 | }; 123 | 124 | // Development module exports 125 | module.exports = [ 126 | merge( 127 | common.legacyConfig, 128 | { 129 | output: { 130 | filename: path.join('./js', '[name]-legacy.[hash].js'), 131 | publicPath: settings.devServerConfig.public() + '/', 132 | }, 133 | mode: 'development', 134 | devtool: 'inline-source-map', 135 | devServer: configureDevServer(LEGACY_CONFIG), 136 | module: { 137 | rules: [ 138 | configurePostcssLoader(LEGACY_CONFIG), 139 | configureImageLoader(LEGACY_CONFIG), 140 | ], 141 | }, 142 | plugins: [ 143 | new webpack.HotModuleReplacementPlugin(), 144 | ], 145 | } 146 | ), 147 | merge( 148 | common.modernConfig, 149 | { 150 | output: { 151 | filename: path.join('./js', '[name].[hash].js'), 152 | publicPath: settings.devServerConfig.public() + '/', 153 | }, 154 | mode: 'development', 155 | devtool: 'inline-source-map', 156 | devServer: configureDevServer(MODERN_CONFIG), 157 | module: { 158 | rules: [ 159 | configurePostcssLoader(MODERN_CONFIG), 160 | configureImageLoader(MODERN_CONFIG), 161 | ], 162 | }, 163 | plugins: [ 164 | new webpack.HotModuleReplacementPlugin(), 165 | new DashboardPlugin(dashboard.setData), 166 | ], 167 | } 168 | ), 169 | ]; 170 | -------------------------------------------------------------------------------- /templates/index.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Welcome to Craft CMS 7 | 8 | 9 | 175 | 176 | 177 |
178 | 216 |
217 | 218 | 219 | -------------------------------------------------------------------------------- /webpack.prod.js: -------------------------------------------------------------------------------- 1 | // webpack.prod.js - production builds 2 | const LEGACY_CONFIG = 'legacy'; 3 | const MODERN_CONFIG = 'modern'; 4 | 5 | // node modules 6 | const git = require('git-rev-sync'); 7 | const glob = require('glob-all'); 8 | const merge = require('webpack-merge'); 9 | const moment = require('moment'); 10 | const path = require('path'); 11 | const webpack = require('webpack'); 12 | 13 | // webpack plugins 14 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 15 | const CleanWebpackPlugin = require('clean-webpack-plugin'); 16 | const CreateSymlinkPlugin = require('create-symlink-webpack-plugin'); 17 | const CriticalCssPlugin = require('critical-css-webpack-plugin'); 18 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 19 | const ImageminWebpWebpackPlugin = require('imagemin-webp-webpack-plugin'); 20 | const MiniCssExtractPlugin = require('mini-css-extract-plugin'); 21 | const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); 22 | const PurgecssPlugin = require('purgecss-webpack-plugin'); 23 | const SaveRemoteFilePlugin = require('save-remote-file-webpack-plugin'); 24 | const TerserPlugin = require('terser-webpack-plugin'); 25 | const WebappWebpackPlugin = require('webapp-webpack-plugin'); 26 | const WhitelisterPlugin = require('purgecss-whitelister'); 27 | const WorkboxPlugin = require('workbox-webpack-plugin'); 28 | 29 | // config files 30 | const common = require('./webpack.common.js'); 31 | const pkg = require('./package.json'); 32 | const settings = require('./webpack.settings.js'); 33 | 34 | // Custom PurgeCSS extractor for Tailwind that allows special characters in 35 | // class names. 36 | // 37 | // https://github.com/FullHuman/purgecss#extractor 38 | class TailwindExtractor { 39 | static extract(content) { 40 | return content.match(/[A-Za-z0-9-_:\/]+/g) || []; 41 | } 42 | } 43 | 44 | // Configure file banner 45 | const configureBanner = () => { 46 | return { 47 | banner: [ 48 | '/*!', 49 | ' * @project ' + settings.name, 50 | ' * @name ' + '[filebase]', 51 | ' * @author ' + pkg.author.name, 52 | ' * @build ' + moment().format('llll') + ' ET', 53 | ' * @release ' + git.long() + ' [' + git.branch() + ']', 54 | ' * @copyright Copyright (c) ' + moment().format('YYYY') + ' ' + settings.copyright, 55 | ' *', 56 | ' */', 57 | '' 58 | ].join('\n'), 59 | raw: true 60 | }; 61 | }; 62 | 63 | // Configure Bundle Analyzer 64 | const configureBundleAnalyzer = (buildType) => { 65 | if (buildType === LEGACY_CONFIG) { 66 | return { 67 | analyzerMode: 'static', 68 | reportFilename: 'report-legacy.html', 69 | }; 70 | } 71 | if (buildType === MODERN_CONFIG) { 72 | return { 73 | analyzerMode: 'static', 74 | reportFilename: 'report-modern.html', 75 | }; 76 | } 77 | }; 78 | 79 | // Configure Critical CSS 80 | const configureCriticalCss = () => { 81 | return (settings.criticalCssConfig.pages.map((row) => { 82 | const criticalSrc = settings.urls.critical + row.url; 83 | const criticalDest = settings.criticalCssConfig.base + row.template + settings.criticalCssConfig.suffix; 84 | let criticalWidth = settings.criticalCssConfig.criticalWidth; 85 | let criticalHeight = settings.criticalCssConfig.criticalHeight; 86 | // Handle Google AMP templates 87 | if (row.template.indexOf(settings.criticalCssConfig.ampPrefix) !== -1) { 88 | criticalWidth = settings.criticalCssConfig.ampCriticalWidth; 89 | criticalHeight = settings.criticalCssConfig.ampCriticalHeight; 90 | } 91 | console.log("source: " + criticalSrc + " dest: " + criticalDest); 92 | return new CriticalCssPlugin({ 93 | base: './', 94 | src: criticalSrc, 95 | dest: criticalDest, 96 | extract: false, 97 | inline: false, 98 | minify: true, 99 | width: criticalWidth, 100 | height: criticalHeight, 101 | }) 102 | }) 103 | ); 104 | }; 105 | 106 | // Configure Clean webpack 107 | const configureCleanWebpack = () => { 108 | return { 109 | root: path.resolve(__dirname, settings.paths.dist.base), 110 | verbose: true, 111 | dry: false 112 | }; 113 | }; 114 | 115 | // Configure Html webpack 116 | const configureHtml = () => { 117 | return { 118 | templateContent: '', 119 | filename: 'webapp.html', 120 | inject: false, 121 | }; 122 | }; 123 | 124 | // Configure Image loader 125 | const configureImageLoader = (buildType) => { 126 | if (buildType === LEGACY_CONFIG) { 127 | return { 128 | test: /\.(png|jpe?g|gif|svg|webp)$/i, 129 | use: [ 130 | { 131 | loader: 'file-loader', 132 | options: { 133 | name: 'img/[name].[hash].[ext]' 134 | } 135 | } 136 | ] 137 | }; 138 | } 139 | if (buildType === MODERN_CONFIG) { 140 | return { 141 | test: /\.(png|jpe?g|gif|svg|webp)$/i, 142 | use: [ 143 | { 144 | loader: 'file-loader', 145 | options: { 146 | name: 'img/[name].[hash].[ext]' 147 | } 148 | }, 149 | { 150 | loader: 'img-loader', 151 | options: { 152 | plugins: [ 153 | require('imagemin-gifsicle')({ 154 | interlaced: true, 155 | }), 156 | require('imagemin-mozjpeg')({ 157 | progressive: true, 158 | arithmetic: false, 159 | }), 160 | require('imagemin-optipng')({ 161 | optimizationLevel: 5, 162 | }), 163 | require('imagemin-svgo')({ 164 | plugins: [ 165 | {convertPathData: false}, 166 | ] 167 | }), 168 | ] 169 | } 170 | } 171 | ] 172 | }; 173 | } 174 | }; 175 | 176 | // Configure optimization 177 | const configureOptimization = (buildType) => { 178 | if (buildType === LEGACY_CONFIG) { 179 | return { 180 | splitChunks: { 181 | cacheGroups: { 182 | default: false, 183 | common: false, 184 | styles: { 185 | name: settings.vars.cssName, 186 | test: /\.(pcss|css|vue)$/, 187 | chunks: 'all', 188 | enforce: true 189 | } 190 | } 191 | }, 192 | minimizer: [ 193 | new TerserPlugin( 194 | configureTerser() 195 | ), 196 | new OptimizeCSSAssetsPlugin({ 197 | cssProcessorOptions: { 198 | map: { 199 | inline: false, 200 | annotation: true, 201 | }, 202 | safe: true, 203 | discardComments: true 204 | }, 205 | }) 206 | ] 207 | }; 208 | } 209 | if (buildType === MODERN_CONFIG) { 210 | return { 211 | minimizer: [ 212 | new TerserPlugin( 213 | configureTerser() 214 | ), 215 | ] 216 | }; 217 | } 218 | }; 219 | 220 | // Configure Postcss loader 221 | const configurePostcssLoader = (buildType) => { 222 | if (buildType === LEGACY_CONFIG) { 223 | return { 224 | test: /\.(pcss|css)$/, 225 | use: [ 226 | MiniCssExtractPlugin.loader, 227 | { 228 | loader: 'css-loader', 229 | options: { 230 | importLoaders: 2, 231 | sourceMap: true 232 | } 233 | }, 234 | { 235 | loader: 'resolve-url-loader' 236 | }, 237 | { 238 | loader: 'postcss-loader', 239 | options: { 240 | sourceMap: true 241 | } 242 | } 243 | ] 244 | }; 245 | } 246 | // Don't generate CSS for the modern config in production 247 | if (buildType === MODERN_CONFIG) { 248 | return { 249 | test: /\.(pcss|css)$/, 250 | loader: 'ignore-loader' 251 | }; 252 | } 253 | }; 254 | 255 | // Configure PurgeCSS 256 | const configurePurgeCss = () => { 257 | let paths = []; 258 | // Configure whitelist paths 259 | for (const [key, value] of Object.entries(settings.purgeCssConfig.paths)) { 260 | paths.push(path.join(__dirname, value)); 261 | } 262 | 263 | return { 264 | paths: glob.sync(paths), 265 | whitelist: WhitelisterPlugin(settings.purgeCssConfig.whitelist), 266 | whitelistPatterns: settings.purgeCssConfig.whitelistPatterns, 267 | extractors: [ 268 | { 269 | extractor: TailwindExtractor, 270 | extensions: settings.purgeCssConfig.extensions 271 | } 272 | ] 273 | }; 274 | }; 275 | 276 | // Configure terser 277 | const configureTerser = () => { 278 | return { 279 | cache: true, 280 | parallel: true, 281 | sourceMap: true 282 | }; 283 | }; 284 | 285 | // Configure Webapp webpack 286 | const configureWebapp = () => { 287 | return { 288 | logo: settings.webappConfig.logo, 289 | prefix: settings.webappConfig.prefix, 290 | cache: false, 291 | inject: 'force', 292 | favicons: { 293 | appName: pkg.name, 294 | appDescription: pkg.description, 295 | developerName: pkg.author.name, 296 | developerURL: pkg.author.url, 297 | path: settings.paths.dist.base, 298 | } 299 | }; 300 | }; 301 | 302 | // Configure Workbox service worker 303 | const configureWorkbox = () => { 304 | let config = settings.workboxConfig; 305 | 306 | return config; 307 | }; 308 | 309 | // Production module exports 310 | module.exports = [ 311 | merge( 312 | common.legacyConfig, 313 | { 314 | output: { 315 | filename: path.join('./js', '[name]-legacy.[chunkhash].js'), 316 | }, 317 | mode: 'production', 318 | devtool: 'source-map', 319 | optimization: configureOptimization(LEGACY_CONFIG), 320 | module: { 321 | rules: [ 322 | configurePostcssLoader(LEGACY_CONFIG), 323 | configureImageLoader(LEGACY_CONFIG), 324 | ], 325 | }, 326 | plugins: [ 327 | new CleanWebpackPlugin(settings.paths.dist.clean, 328 | configureCleanWebpack() 329 | ), 330 | new MiniCssExtractPlugin({ 331 | path: path.resolve(__dirname, settings.paths.dist.base), 332 | filename: path.join('./css', '[name].[chunkhash].css'), 333 | }), 334 | new PurgecssPlugin( 335 | configurePurgeCss() 336 | ), 337 | new webpack.BannerPlugin( 338 | configureBanner() 339 | ), 340 | new HtmlWebpackPlugin( 341 | configureHtml() 342 | ), 343 | new WebappWebpackPlugin( 344 | configureWebapp() 345 | ), 346 | new CreateSymlinkPlugin( 347 | settings.createSymlinkConfig, 348 | true 349 | ), 350 | new SaveRemoteFilePlugin( 351 | settings.saveRemoteFileConfig 352 | ), 353 | new BundleAnalyzerPlugin( 354 | configureBundleAnalyzer(LEGACY_CONFIG), 355 | ), 356 | ].concat( 357 | configureCriticalCss() 358 | ) 359 | } 360 | ), 361 | merge( 362 | common.modernConfig, 363 | { 364 | output: { 365 | filename: path.join('./js', '[name].[chunkhash].js'), 366 | }, 367 | mode: 'production', 368 | devtool: 'source-map', 369 | optimization: configureOptimization(MODERN_CONFIG), 370 | module: { 371 | rules: [ 372 | configurePostcssLoader(MODERN_CONFIG), 373 | configureImageLoader(MODERN_CONFIG), 374 | ], 375 | }, 376 | plugins: [ 377 | new webpack.optimize.ModuleConcatenationPlugin(), 378 | new webpack.BannerPlugin( 379 | configureBanner() 380 | ), 381 | new ImageminWebpWebpackPlugin(), 382 | new WorkboxPlugin.GenerateSW( 383 | configureWorkbox() 384 | ), 385 | new BundleAnalyzerPlugin( 386 | configureBundleAnalyzer(MODERN_CONFIG), 387 | ), 388 | ] 389 | } 390 | ), 391 | ]; 392 | -------------------------------------------------------------------------------- /tailwind.config.js: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Tailwind - The Utility-First CSS Framework 4 | 5 | A project by Adam Wathan (@adamwathan), Jonathan Reinink (@reinink), 6 | David Hemphill (@davidhemphill) and Steve Schoger (@steveschoger). 7 | 8 | Welcome to the Tailwind config file. This is where you can customize 9 | Tailwind specifically for your project. Don't be intimidated by the 10 | length of this file. It's really just a big JavaScript object and 11 | we've done our very best to explain each section. 12 | 13 | View the full documentation at https://tailwindcss.com. 14 | 15 | 16 | |------------------------------------------------------------------------------- 17 | | The default config 18 | |------------------------------------------------------------------------------- 19 | | 20 | | This variable contains the default Tailwind config. You don't have 21 | | to use it, but it can sometimes be helpful to have available. For 22 | | example, you may choose to merge your custom configuration 23 | | values with some of the Tailwind defaults. 24 | | 25 | */ 26 | 27 | // let defaultConfig = require('tailwindcss/defaultConfig')() 28 | 29 | 30 | /* 31 | |------------------------------------------------------------------------------- 32 | | Colors https://tailwindcss.com/docs/colors 33 | |------------------------------------------------------------------------------- 34 | | 35 | | Here you can specify the colors used in your project. To get you started, 36 | | we've provided a generous palette of great looking colors that are perfect 37 | | for prototyping, but don't hesitate to change them for your project. You 38 | | own these colors, nothing will break if you change everything about them. 39 | | 40 | | We've used literal color names ("red", "blue", etc.) for the default 41 | | palette, but if you'd rather use functional names like "primary" and 42 | | "secondary", or even a numeric scale like "100" and "200", go for it. 43 | | 44 | */ 45 | 46 | let colors = { 47 | 'transparent': 'transparent', 48 | 49 | 'black': '#22292f', 50 | 'grey-darkest': '#3d4852', 51 | 'grey-darker': '#606f7b', 52 | 'grey-dark': '#8795a1', 53 | 'grey': '#b8c2cc', 54 | 'grey-light': '#dae1e7', 55 | 'grey-lighter': '#f1f5f8', 56 | 'grey-lightest': '#f8fafc', 57 | 'white': '#ffffff', 58 | 59 | 'red-darkest': '#3b0d0c', 60 | 'red-darker': '#621b18', 61 | 'red-dark': '#cc1f1a', 62 | 'red': '#e3342f', 63 | 'red-light': '#ef5753', 64 | 'red-lighter': '#f9acaa', 65 | 'red-lightest': '#fcebea', 66 | 67 | 'orange-darkest': '#462a16', 68 | 'orange-darker': '#613b1f', 69 | 'orange-dark': '#de751f', 70 | 'orange': '#f6993f', 71 | 'orange-light': '#faad63', 72 | 'orange-lighter': '#fcd9b6', 73 | 'orange-lightest': '#fff5eb', 74 | 75 | 'yellow-darkest': '#453411', 76 | 'yellow-darker': '#684f1d', 77 | 'yellow-dark': '#f2d024', 78 | 'yellow': '#ffed4a', 79 | 'yellow-light': '#fff382', 80 | 'yellow-lighter': '#fff9c2', 81 | 'yellow-lightest': '#fcfbeb', 82 | 83 | 'green-darkest': '#0f2f21', 84 | 'green-darker': '#1a4731', 85 | 'green-dark': '#1f9d55', 86 | 'green': '#38c172', 87 | 'green-light': '#51d88a', 88 | 'green-lighter': '#a2f5bf', 89 | 'green-lightest': '#e3fcec', 90 | 91 | 'teal-darkest': '#0d3331', 92 | 'teal-darker': '#20504f', 93 | 'teal-dark': '#38a89d', 94 | 'teal': '#4dc0b5', 95 | 'teal-light': '#64d5ca', 96 | 'teal-lighter': '#a0f0ed', 97 | 'teal-lightest': '#e8fffe', 98 | 99 | 'blue-darkest': '#12283a', 100 | 'blue-darker': '#1c3d5a', 101 | 'blue-dark': '#2779bd', 102 | 'blue': '#3490dc', 103 | 'blue-light': '#6cb2eb', 104 | 'blue-lighter': '#bcdefa', 105 | 'blue-lightest': '#eff8ff', 106 | 107 | 'indigo-darkest': '#191e38', 108 | 'indigo-darker': '#2f365f', 109 | 'indigo-dark': '#5661b3', 110 | 'indigo': '#6574cd', 111 | 'indigo-light': '#7886d7', 112 | 'indigo-lighter': '#b2b7ff', 113 | 'indigo-lightest': '#e6e8ff', 114 | 115 | 'purple-darkest': '#21183c', 116 | 'purple-darker': '#382b5f', 117 | 'purple-dark': '#794acf', 118 | 'purple': '#9561e2', 119 | 'purple-light': '#a779e9', 120 | 'purple-lighter': '#d6bbfc', 121 | 'purple-lightest': '#f3ebff', 122 | 123 | 'pink-darkest': '#451225', 124 | 'pink-darker': '#6f213f', 125 | 'pink-dark': '#eb5286', 126 | 'pink': '#f66d9b', 127 | 'pink-light': '#fa7ea8', 128 | 'pink-lighter': '#ffbbca', 129 | 'pink-lightest': '#ffebef', 130 | } 131 | 132 | module.exports = { 133 | 134 | /* 135 | |----------------------------------------------------------------------------- 136 | | Colors https://tailwindcss.com/docs/colors 137 | |----------------------------------------------------------------------------- 138 | | 139 | | The color palette defined above is also assigned to the "colors" key of 140 | | your Tailwind config. This makes it easy to access them in your CSS 141 | | using Tailwind's config helper. For example: 142 | | 143 | | .error { color: config('colors.red') } 144 | | 145 | */ 146 | 147 | colors: colors, 148 | 149 | 150 | /* 151 | |----------------------------------------------------------------------------- 152 | | Screens https://tailwindcss.com/docs/responsive-design 153 | |----------------------------------------------------------------------------- 154 | | 155 | | Screens in Tailwind are translated to CSS media queries. They define the 156 | | responsive breakpoints for your project. By default Tailwind takes a 157 | | "mobile first" approach, where each screen size represents a minimum 158 | | viewport width. Feel free to have as few or as many screens as you 159 | | want, naming them in whatever way you'd prefer for your project. 160 | | 161 | | Tailwind also allows for more complex screen definitions, which can be 162 | | useful in certain situations. Be sure to see the full responsive 163 | | documentation for a complete list of options. 164 | | 165 | | Class name: .{screen}:{utility} 166 | | 167 | */ 168 | 169 | screens: { 170 | 'sm': '576px', 171 | 'md': '768px', 172 | 'lg': '992px', 173 | 'xl': '1200px', 174 | }, 175 | 176 | 177 | /* 178 | |----------------------------------------------------------------------------- 179 | | Fonts https://tailwindcss.com/docs/fonts 180 | |----------------------------------------------------------------------------- 181 | | 182 | | Here is where you define your project's font stack, or font families. 183 | | Keep in mind that Tailwind doesn't actually load any fonts for you. 184 | | If you're using custom fonts you'll need to import them prior to 185 | | defining them here. 186 | | 187 | | By default we provide a native font stack that works remarkably well on 188 | | any device or OS you're using, since it just uses the default fonts 189 | | provided by the platform. 190 | | 191 | | Class name: .font-{name} 192 | | 193 | */ 194 | 195 | fonts: { 196 | 'sans': [ 197 | 'system-ui', 198 | 'BlinkMacSystemFont', 199 | '-apple-system', 200 | 'Segoe UI', 201 | 'Roboto', 202 | 'Oxygen', 203 | 'Ubuntu', 204 | 'Cantarell', 205 | 'Fira Sans', 206 | 'Droid Sans', 207 | 'Helvetica Neue', 208 | 'sans-serif', 209 | ], 210 | 'serif': [ 211 | 'Constantia', 212 | 'Lucida Bright', 213 | 'Lucidabright', 214 | 'Lucida Serif', 215 | 'Lucida', 216 | 'DejaVu Serif', 217 | 'Bitstream Vera Serif', 218 | 'Liberation Serif', 219 | 'Georgia', 220 | 'serif', 221 | ], 222 | 'mono': [ 223 | 'Menlo', 224 | 'Monaco', 225 | 'Consolas', 226 | 'Liberation Mono', 227 | 'Courier New', 228 | 'monospace', 229 | ] 230 | }, 231 | 232 | 233 | /* 234 | |----------------------------------------------------------------------------- 235 | | Text sizes https://tailwindcss.com/docs/text-sizing 236 | |----------------------------------------------------------------------------- 237 | | 238 | | Here is where you define your text sizes. Name these in whatever way 239 | | makes the most sense to you. We use size names by default, but 240 | | you're welcome to use a numeric scale or even something else 241 | | entirely. 242 | | 243 | | By default Tailwind uses the "rem" unit type for most measurements. 244 | | This allows you to set a root font size which all other sizes are 245 | | then based on. That said, you are free to use whatever units you 246 | | prefer, be it rems, ems, pixels or other. 247 | | 248 | | Class name: .text-{size} 249 | | 250 | */ 251 | 252 | textSizes: { 253 | 'xs': '.75rem', // 12px 254 | 'sm': '.875rem', // 14px 255 | 'base': '1rem', // 16px 256 | 'lg': '1.125rem', // 18px 257 | 'xl': '1.25rem', // 20px 258 | '2xl': '1.5rem', // 24px 259 | '3xl': '1.875rem', // 30px 260 | '4xl': '2.25rem', // 36px 261 | '5xl': '3rem', // 48px 262 | }, 263 | 264 | 265 | /* 266 | |----------------------------------------------------------------------------- 267 | | Font weights https://tailwindcss.com/docs/font-weight 268 | |----------------------------------------------------------------------------- 269 | | 270 | | Here is where you define your font weights. We've provided a list of 271 | | common font weight names with their respective numeric scale values 272 | | to get you started. It's unlikely that your project will require 273 | | all of these, so we recommend removing those you don't need. 274 | | 275 | | Class name: .font-{weight} 276 | | 277 | */ 278 | 279 | fontWeights: { 280 | 'hairline': 100, 281 | 'thin': 200, 282 | 'light': 300, 283 | 'normal': 400, 284 | 'medium': 500, 285 | 'semibold': 600, 286 | 'bold': 700, 287 | 'extrabold': 800, 288 | 'black': 900, 289 | }, 290 | 291 | 292 | /* 293 | |----------------------------------------------------------------------------- 294 | | Leading (line height) https://tailwindcss.com/docs/line-height 295 | |----------------------------------------------------------------------------- 296 | | 297 | | Here is where you define your line height values, or as we call 298 | | them in Tailwind, leadings. 299 | | 300 | | Class name: .leading-{size} 301 | | 302 | */ 303 | 304 | leading: { 305 | 'none': 1, 306 | 'tight': 1.25, 307 | 'normal': 1.5, 308 | 'loose': 2, 309 | }, 310 | 311 | 312 | /* 313 | |----------------------------------------------------------------------------- 314 | | Tracking (letter spacing) https://tailwindcss.com/docs/letter-spacing 315 | |----------------------------------------------------------------------------- 316 | | 317 | | Here is where you define your letter spacing values, or as we call 318 | | them in Tailwind, tracking. 319 | | 320 | | Class name: .tracking-{size} 321 | | 322 | */ 323 | 324 | tracking: { 325 | 'tight': '-0.05em', 326 | 'normal': '0', 327 | 'wide': '0.05em', 328 | }, 329 | 330 | 331 | /* 332 | |----------------------------------------------------------------------------- 333 | | Text colors https://tailwindcss.com/docs/text-color 334 | |----------------------------------------------------------------------------- 335 | | 336 | | Here is where you define your text colors. By default these use the 337 | | color palette we defined above, however you're welcome to set these 338 | | independently if that makes sense for your project. 339 | | 340 | | Class name: .text-{color} 341 | | 342 | */ 343 | 344 | textColors: colors, 345 | 346 | 347 | /* 348 | |----------------------------------------------------------------------------- 349 | | Background colors https://tailwindcss.com/docs/background-color 350 | |----------------------------------------------------------------------------- 351 | | 352 | | Here is where you define your background colors. By default these use 353 | | the color palette we defined above, however you're welcome to set 354 | | these independently if that makes sense for your project. 355 | | 356 | | Class name: .bg-{color} 357 | | 358 | */ 359 | 360 | backgroundColors: colors, 361 | 362 | 363 | /* 364 | |----------------------------------------------------------------------------- 365 | | Background sizes https://tailwindcss.com/docs/background-size 366 | |----------------------------------------------------------------------------- 367 | | 368 | | Here is where you define your background sizes. We provide some common 369 | | values that are useful in most projects, but feel free to add other sizes 370 | | that are specific to your project here as well. 371 | | 372 | | Class name: .bg-{size} 373 | | 374 | */ 375 | 376 | backgroundSize: { 377 | 'auto': 'auto', 378 | 'cover': 'cover', 379 | 'contain': 'contain', 380 | }, 381 | 382 | 383 | /* 384 | |----------------------------------------------------------------------------- 385 | | Border widths https://tailwindcss.com/docs/border-width 386 | |----------------------------------------------------------------------------- 387 | | 388 | | Here is where you define your border widths. Take note that border 389 | | widths require a special "default" value set as well. This is the 390 | | width that will be used when you do not specify a border width. 391 | | 392 | | Class name: .border{-side?}{-width?} 393 | | 394 | */ 395 | 396 | borderWidths: { 397 | default: '1px', 398 | '0': '0', 399 | '2': '2px', 400 | '4': '4px', 401 | '8': '8px', 402 | }, 403 | 404 | 405 | /* 406 | |----------------------------------------------------------------------------- 407 | | Border colors https://tailwindcss.com/docs/border-color 408 | |----------------------------------------------------------------------------- 409 | | 410 | | Here is where you define your border colors. By default these use the 411 | | color palette we defined above, however you're welcome to set these 412 | | independently if that makes sense for your project. 413 | | 414 | | Take note that border colors require a special "default" value set 415 | | as well. This is the color that will be used when you do not 416 | | specify a border color. 417 | | 418 | | Class name: .border-{color} 419 | | 420 | */ 421 | 422 | borderColors: global.Object.assign({ default: colors['grey-light'] }, colors), 423 | 424 | 425 | /* 426 | |----------------------------------------------------------------------------- 427 | | Border radius https://tailwindcss.com/docs/border-radius 428 | |----------------------------------------------------------------------------- 429 | | 430 | | Here is where you define your border radius values. If a `default` radius 431 | | is provided, it will be made available as the non-suffixed `.rounded` 432 | | utility. 433 | | 434 | | If your scale includes a `0` value to reset already rounded corners, it's 435 | | a good idea to put it first so other values are able to override it. 436 | | 437 | | Class name: .rounded{-side?}{-size?} 438 | | 439 | */ 440 | 441 | borderRadius: { 442 | 'none': '0', 443 | 'sm': '.125rem', 444 | default: '.25rem', 445 | 'lg': '.5rem', 446 | 'full': '9999px', 447 | }, 448 | 449 | 450 | /* 451 | |----------------------------------------------------------------------------- 452 | | Width https://tailwindcss.com/docs/width 453 | |----------------------------------------------------------------------------- 454 | | 455 | | Here is where you define your width utility sizes. These can be 456 | | percentage based, pixels, rems, or any other units. By default 457 | | we provide a sensible rem based numeric scale, a percentage 458 | | based fraction scale, plus some other common use-cases. You 459 | | can, of course, modify these values as needed. 460 | | 461 | | 462 | | It's also worth mentioning that Tailwind automatically escapes 463 | | invalid CSS class name characters, which allows you to have 464 | | awesome classes like .w-2/3. 465 | | 466 | | Class name: .w-{size} 467 | | 468 | */ 469 | 470 | width: { 471 | 'auto': 'auto', 472 | 'px': '1px', 473 | '1': '0.25rem', 474 | '2': '0.5rem', 475 | '3': '0.75rem', 476 | '4': '1rem', 477 | '5': '1.25rem', 478 | '6': '1.5rem', 479 | '8': '2rem', 480 | '10': '2.5rem', 481 | '12': '3rem', 482 | '16': '4rem', 483 | '24': '6rem', 484 | '32': '8rem', 485 | '48': '12rem', 486 | '64': '16rem', 487 | '1/2': '50%', 488 | '1/3': '33.33333%', 489 | '2/3': '66.66667%', 490 | '1/4': '25%', 491 | '3/4': '75%', 492 | '1/5': '20%', 493 | '2/5': '40%', 494 | '3/5': '60%', 495 | '4/5': '80%', 496 | '1/6': '16.66667%', 497 | '5/6': '83.33333%', 498 | 'full': '100%', 499 | 'screen': '100vw' 500 | }, 501 | 502 | 503 | /* 504 | |----------------------------------------------------------------------------- 505 | | Height https://tailwindcss.com/docs/height 506 | |----------------------------------------------------------------------------- 507 | | 508 | | Here is where you define your height utility sizes. These can be 509 | | percentage based, pixels, rems, or any other units. By default 510 | | we provide a sensible rem based numeric scale plus some other 511 | | common use-cases. You can, of course, modify these values as 512 | | needed. 513 | | 514 | | Class name: .h-{size} 515 | | 516 | */ 517 | 518 | height: { 519 | 'auto': 'auto', 520 | 'px': '1px', 521 | '1': '0.25rem', 522 | '2': '0.5rem', 523 | '3': '0.75rem', 524 | '4': '1rem', 525 | '5': '1.25rem', 526 | '6': '1.5rem', 527 | '8': '2rem', 528 | '10': '2.5rem', 529 | '12': '3rem', 530 | '16': '4rem', 531 | '24': '6rem', 532 | '32': '8rem', 533 | '48': '12rem', 534 | '64': '16rem', 535 | 'full': '100%', 536 | 'screen': '100vh' 537 | }, 538 | 539 | 540 | /* 541 | |----------------------------------------------------------------------------- 542 | | Minimum width https://tailwindcss.com/docs/min-width 543 | |----------------------------------------------------------------------------- 544 | | 545 | | Here is where you define your minimum width utility sizes. These can 546 | | be percentage based, pixels, rems, or any other units. We provide a 547 | | couple common use-cases by default. You can, of course, modify 548 | | these values as needed. 549 | | 550 | | Class name: .min-w-{size} 551 | | 552 | */ 553 | 554 | minWidth: { 555 | '0': '0', 556 | 'full': '100%', 557 | }, 558 | 559 | 560 | /* 561 | |----------------------------------------------------------------------------- 562 | | Minimum height https://tailwindcss.com/docs/min-height 563 | |----------------------------------------------------------------------------- 564 | | 565 | | Here is where you define your minimum height utility sizes. These can 566 | | be percentage based, pixels, rems, or any other units. We provide a 567 | | few common use-cases by default. You can, of course, modify these 568 | | values as needed. 569 | | 570 | | Class name: .min-h-{size} 571 | | 572 | */ 573 | 574 | minHeight: { 575 | '0': '0', 576 | 'full': '100%', 577 | 'screen': '100vh' 578 | }, 579 | 580 | 581 | /* 582 | |----------------------------------------------------------------------------- 583 | | Maximum width https://tailwindcss.com/docs/max-width 584 | |----------------------------------------------------------------------------- 585 | | 586 | | Here is where you define your maximum width utility sizes. These can 587 | | be percentage based, pixels, rems, or any other units. By default 588 | | we provide a sensible rem based scale and a "full width" size, 589 | | which is basically a reset utility. You can, of course, 590 | | modify these values as needed. 591 | | 592 | | Class name: .max-w-{size} 593 | | 594 | */ 595 | 596 | maxWidth: { 597 | 'xs': '20rem', 598 | 'sm': '30rem', 599 | 'md': '40rem', 600 | 'lg': '50rem', 601 | 'xl': '60rem', 602 | '2xl': '70rem', 603 | '3xl': '80rem', 604 | '4xl': '90rem', 605 | '5xl': '100rem', 606 | 'full': '100%', 607 | }, 608 | 609 | 610 | /* 611 | |----------------------------------------------------------------------------- 612 | | Maximum height https://tailwindcss.com/docs/max-height 613 | |----------------------------------------------------------------------------- 614 | | 615 | | Here is where you define your maximum height utility sizes. These can 616 | | be percentage based, pixels, rems, or any other units. We provide a 617 | | couple common use-cases by default. You can, of course, modify 618 | | these values as needed. 619 | | 620 | | Class name: .max-h-{size} 621 | | 622 | */ 623 | 624 | maxHeight: { 625 | 'full': '100%', 626 | 'screen': '100vh', 627 | }, 628 | 629 | 630 | /* 631 | |----------------------------------------------------------------------------- 632 | | Padding https://tailwindcss.com/docs/padding 633 | |----------------------------------------------------------------------------- 634 | | 635 | | Here is where you define your padding utility sizes. These can be 636 | | percentage based, pixels, rems, or any other units. By default we 637 | | provide a sensible rem based numeric scale plus a couple other 638 | | common use-cases like "1px". You can, of course, modify these 639 | | values as needed. 640 | | 641 | | Class name: .p{side?}-{size} 642 | | 643 | */ 644 | 645 | padding: { 646 | 'px': '1px', 647 | '0': '0', 648 | '1': '0.25rem', 649 | '2': '0.5rem', 650 | '3': '0.75rem', 651 | '4': '1rem', 652 | '5': '1.25rem', 653 | '6': '1.5rem', 654 | '8': '2rem', 655 | '10': '2.5rem', 656 | '12': '3rem', 657 | '16': '4rem', 658 | '20': '5rem', 659 | '24': '6rem', 660 | '32': '8rem', 661 | }, 662 | 663 | 664 | /* 665 | |----------------------------------------------------------------------------- 666 | | Margin https://tailwindcss.com/docs/margin 667 | |----------------------------------------------------------------------------- 668 | | 669 | | Here is where you define your margin utility sizes. These can be 670 | | percentage based, pixels, rems, or any other units. By default we 671 | | provide a sensible rem based numeric scale plus a couple other 672 | | common use-cases like "1px". You can, of course, modify these 673 | | values as needed. 674 | | 675 | | Class name: .m{side?}-{size} 676 | | 677 | */ 678 | 679 | margin: { 680 | 'auto': 'auto', 681 | 'px': '1px', 682 | '0': '0', 683 | '1': '0.25rem', 684 | '2': '0.5rem', 685 | '3': '0.75rem', 686 | '4': '1rem', 687 | '5': '1.25rem', 688 | '6': '1.5rem', 689 | '8': '2rem', 690 | '10': '2.5rem', 691 | '12': '3rem', 692 | '16': '4rem', 693 | '20': '5rem', 694 | '24': '6rem', 695 | '32': '8rem', 696 | }, 697 | 698 | 699 | /* 700 | |----------------------------------------------------------------------------- 701 | | Negative margin https://tailwindcss.com/docs/negative-margin 702 | |----------------------------------------------------------------------------- 703 | | 704 | | Here is where you define your negative margin utility sizes. These can 705 | | be percentage based, pixels, rems, or any other units. By default we 706 | | provide matching values to the padding scale since these utilities 707 | | generally get used together. You can, of course, modify these 708 | | values as needed. 709 | | 710 | | Class name: .-m{side?}-{size} 711 | | 712 | */ 713 | 714 | negativeMargin: { 715 | 'px': '1px', 716 | '0': '0', 717 | '1': '0.25rem', 718 | '2': '0.5rem', 719 | '3': '0.75rem', 720 | '4': '1rem', 721 | '5': '1.25rem', 722 | '6': '1.5rem', 723 | '8': '2rem', 724 | '10': '2.5rem', 725 | '12': '3rem', 726 | '16': '4rem', 727 | '20': '5rem', 728 | '24': '6rem', 729 | '32': '8rem', 730 | }, 731 | 732 | 733 | /* 734 | |----------------------------------------------------------------------------- 735 | | Shadows https://tailwindcss.com/docs/shadows 736 | |----------------------------------------------------------------------------- 737 | | 738 | | Here is where you define your shadow utilities. As you can see from 739 | | the defaults we provide, it's possible to apply multiple shadows 740 | | per utility using comma separation. 741 | | 742 | | If a `default` shadow is provided, it will be made available as the non- 743 | | suffixed `.shadow` utility. 744 | | 745 | | Class name: .shadow-{size?} 746 | | 747 | */ 748 | 749 | shadows: { 750 | default: '0 2px 4px 0 rgba(0,0,0,0.10)', 751 | 'md': '0 4px 8px 0 rgba(0,0,0,0.12), 0 2px 4px 0 rgba(0,0,0,0.08)', 752 | 'lg': '0 15px 30px 0 rgba(0,0,0,0.11), 0 5px 15px 0 rgba(0,0,0,0.08)', 753 | 'inner': 'inset 0 2px 4px 0 rgba(0,0,0,0.06)', 754 | 'outline': '0 0 0 3px rgba(52,144,220,0.5)', 755 | 'none': 'none', 756 | }, 757 | 758 | 759 | /* 760 | |----------------------------------------------------------------------------- 761 | | Z-index https://tailwindcss.com/docs/z-index 762 | |----------------------------------------------------------------------------- 763 | | 764 | | Here is where you define your z-index utility values. By default we 765 | | provide a sensible numeric scale. You can, of course, modify these 766 | | values as needed. 767 | | 768 | | Class name: .z-{index} 769 | | 770 | */ 771 | 772 | zIndex: { 773 | 'auto': 'auto', 774 | '0': 0, 775 | '10': 10, 776 | '20': 20, 777 | '30': 30, 778 | '40': 40, 779 | '50': 50, 780 | }, 781 | 782 | 783 | /* 784 | |----------------------------------------------------------------------------- 785 | | Opacity https://tailwindcss.com/docs/opacity 786 | |----------------------------------------------------------------------------- 787 | | 788 | | Here is where you define your opacity utility values. By default we 789 | | provide a sensible numeric scale. You can, of course, modify these 790 | | values as needed. 791 | | 792 | | Class name: .opacity-{name} 793 | | 794 | */ 795 | 796 | opacity: { 797 | '0': '0', 798 | '25': '.25', 799 | '50': '.5', 800 | '75': '.75', 801 | '100': '1', 802 | }, 803 | 804 | 805 | /* 806 | |----------------------------------------------------------------------------- 807 | | SVG fill https://tailwindcss.com/docs/svg 808 | |----------------------------------------------------------------------------- 809 | | 810 | | Here is where you define your SVG fill colors. By default we just provide 811 | | `fill-current` which sets the fill to the current text color. This lets you 812 | | specify a fill color using existing text color utilities and helps keep the 813 | | generated CSS file size down. 814 | | 815 | | Class name: .fill-{name} 816 | | 817 | */ 818 | 819 | svgFill: { 820 | 'current': 'currentColor', 821 | }, 822 | 823 | 824 | /* 825 | |----------------------------------------------------------------------------- 826 | | SVG stroke https://tailwindcss.com/docs/svg 827 | |----------------------------------------------------------------------------- 828 | | 829 | | Here is where you define your SVG stroke colors. By default we just provide 830 | | `stroke-current` which sets the stroke to the current text color. This lets 831 | | you specify a stroke color using existing text color utilities and helps 832 | | keep the generated CSS file size down. 833 | | 834 | | Class name: .stroke-{name} 835 | | 836 | */ 837 | 838 | svgStroke: { 839 | 'current': 'currentColor', 840 | }, 841 | 842 | 843 | /* 844 | |----------------------------------------------------------------------------- 845 | | Modules https://tailwindcss.com/docs/configuration#modules 846 | |----------------------------------------------------------------------------- 847 | | 848 | | Here is where you control which modules are generated and what variants are 849 | | generated for each of those modules. 850 | | 851 | | Currently supported variants: 852 | | - responsive 853 | | - hover 854 | | - focus 855 | | - active 856 | | - group-hover 857 | | 858 | | To disable a module completely, use `false` instead of an array. 859 | | 860 | */ 861 | 862 | modules: { 863 | appearance: ['responsive'], 864 | backgroundAttachment: ['responsive'], 865 | backgroundColors: ['responsive', 'hover', 'focus'], 866 | backgroundPosition: ['responsive'], 867 | backgroundRepeat: ['responsive'], 868 | backgroundSize: ['responsive'], 869 | borderCollapse: [], 870 | borderColors: ['responsive', 'hover', 'focus'], 871 | borderRadius: ['responsive'], 872 | borderStyle: ['responsive'], 873 | borderWidths: ['responsive'], 874 | cursor: ['responsive'], 875 | display: ['responsive'], 876 | flexbox: ['responsive'], 877 | float: ['responsive'], 878 | fonts: ['responsive'], 879 | fontWeights: ['responsive', 'hover', 'focus'], 880 | height: ['responsive'], 881 | leading: ['responsive'], 882 | lists: ['responsive'], 883 | margin: ['responsive'], 884 | maxHeight: ['responsive'], 885 | maxWidth: ['responsive'], 886 | minHeight: ['responsive'], 887 | minWidth: ['responsive'], 888 | negativeMargin: ['responsive'], 889 | opacity: ['responsive'], 890 | outline: ['focus'], 891 | overflow: ['responsive'], 892 | padding: ['responsive'], 893 | pointerEvents: ['responsive'], 894 | position: ['responsive'], 895 | resize: ['responsive'], 896 | shadows: ['responsive', 'hover', 'focus'], 897 | svgFill: [], 898 | svgStroke: [], 899 | tableLayout: ['responsive'], 900 | textAlign: ['responsive'], 901 | textColors: ['responsive', 'hover', 'focus'], 902 | textSizes: ['responsive'], 903 | textStyle: ['responsive', 'hover', 'focus'], 904 | tracking: ['responsive'], 905 | userSelect: ['responsive'], 906 | verticalAlign: ['responsive'], 907 | visibility: ['responsive'], 908 | whitespace: ['responsive'], 909 | width: ['responsive'], 910 | zIndex: ['responsive'], 911 | }, 912 | 913 | 914 | /* 915 | |----------------------------------------------------------------------------- 916 | | Plugins https://tailwindcss.com/docs/plugins 917 | |----------------------------------------------------------------------------- 918 | | 919 | | Here is where you can register any plugins you'd like to use in your 920 | | project. Tailwind's built-in `container` plugin is enabled by default to 921 | | give you a Bootstrap-style responsive container component out of the box. 922 | | 923 | | Be sure to view the complete plugin documentation to learn more about how 924 | | the plugin system works. 925 | | 926 | */ 927 | 928 | plugins: [ 929 | require('tailwindcss/plugins/container')({ 930 | // center: true, 931 | // padding: '1rem', 932 | }), 933 | ], 934 | 935 | 936 | /* 937 | |----------------------------------------------------------------------------- 938 | | Advanced Options https://tailwindcss.com/docs/configuration#options 939 | |----------------------------------------------------------------------------- 940 | | 941 | | Here is where you can tweak advanced configuration options. We recommend 942 | | leaving these options alone unless you absolutely need to change them. 943 | | 944 | */ 945 | 946 | options: { 947 | prefix: '', 948 | important: false, 949 | separator: ':', 950 | }, 951 | 952 | } 953 | --------------------------------------------------------------------------------