├── .babelrc
├── .browserslistrc
├── .gitignore
├── .htaccess
├── LICENSE
├── README.md
├── configs
└── workbox.js
├── dist
├── pwa
│ └── manifest.json
└── site-icon
│ └── app-logo.png
├── package.json
├── postcss.config.js
├── src
├── icons
│ └── technology.svg
├── imgs
│ └── technology.png
├── js
│ ├── App.vue
│ ├── components
│ │ ├── global
│ │ │ ├── Footer.vue
│ │ │ ├── Navbar.vue
│ │ │ └── NotFound.vue
│ │ └── pages
│ │ │ └── Main.vue
│ ├── index.js
│ ├── routes
│ │ └── route.js
│ └── store
│ │ ├── index.js
│ │ ├── modules
│ │ └── draft.js
│ │ └── utils
│ │ ├── api.js
│ │ └── asyncData.js
├── scss
│ ├── components
│ │ ├── _global.scss
│ │ ├── freq
│ │ │ └── _frequest.scss
│ │ ├── utils
│ │ │ ├── _fonts.scss
│ │ │ ├── _media.scss
│ │ │ └── _variables.scss
│ │ └── vendor
│ │ │ └── _bootstrap-grid.scss
│ └── index.scss
└── template
│ └── index.template.ejs
├── webpack.dev.config.js
├── webpack.prod.config.js
└── yarn.lock
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | [
4 | "@babel/preset-env",
5 | {
6 | "corejs": 3,
7 | "modules": false,
8 | "loose": false,
9 | "targets": {
10 | "browsers": [
11 | "> 0.4%",
12 | "not IE 11",
13 | "not OperaMini all",
14 | "not IE_Mob 11",
15 | "edge >= 12",
16 | "chrome >= 30",
17 | "Samsung > 9.2",
18 | "chromeandroid >= 58",
19 | "android >= 10",
20 | "ff >= 60",
21 | "safari >= 11.1",
22 | "ios >= 11.1",
23 | "opera >= 62"
24 | ]
25 | }
26 | }
27 | ]
28 | ],
29 | "plugins": [
30 | [
31 | "@babel/plugin-transform-runtime",
32 | {
33 | "helpers": false,
34 | "regenerator": true,
35 | "useESModules": false,
36 | "version": "7.0.0-beta.0",
37 | "absolutePath": false
38 | }
39 | ]
40 | ],
41 | "minified": true
42 | }
43 |
--------------------------------------------------------------------------------
/.browserslistrc:
--------------------------------------------------------------------------------
1 | > 0.4%,
2 | not IE 11,
3 | not OperaMini all,
4 | not IE_Mob 11,
5 | edge >= 12,
6 | chrome >= 30,
7 | Samsung > 9.2,
8 | chromeandroid >= 58,
9 | android >= 10,
10 | ff >= 60,
11 | safari >= 11.1,
12 | ios >= 11.1,
13 | opera >= 62
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Logs
2 | logs
3 | *.log
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | pids
8 | *.pid
9 | *.seed
10 | *.pid.lock
11 | lib-cov
12 | coverage
13 | .nyc_output
14 | .grunt
15 | bower_components
16 | .lock-wscript
17 | build/Release
18 | node_modules/
19 | jspm_packages/
20 | typings/
21 | .npm
22 | .eslintcache
23 | .node_repl_history
24 | *.tgz
25 | .yarn-integrity
26 | .env
27 | .next
28 | .lock
29 | .idea
30 | *.lock
31 |
--------------------------------------------------------------------------------
/.htaccess:
--------------------------------------------------------------------------------
1 |
2 | RewriteEngine On
3 | RewriteBase /
4 | RewriteRule ^index\.html$ - [L]
5 | RewriteCond %{REQUEST_FILENAME} !-f
6 | RewriteCond %{REQUEST_FILENAME} !-d
7 | RewriteRule . /dist/index.html [L]
8 |
9 |
10 | mod_gzip_on Yes
11 | mod_gzip_dechunk Yes
12 | mod_gzip_item_include file \.(html?|txt|css|js|php|pl)$
13 | mod_gzip_item_include handler ^cgi-script$
14 | mod_gzip_item_include mime ^text\.*
15 | mod_gzip_item_include mime ^application/x-javascript.*
16 | mod_gzip_item_exclude mime ^image\.*
17 | mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
18 |
19 | AddOutputFilterByType DEFLATE text/html
20 | AddOutputFilterByType DEFLATE text/plain
21 | AddOutputFilterByType DEFLATE application/javascript
22 | AddOutputFilterByType DEFLATE application/rss+xml
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Kenan
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Vue & PWA ready app template
2 |
3 | ### Main commands
4 |
5 | ```yarn || npm i ( install )``` - dowload dependencies
6 | ```yarn dev || npm run dev``` - Dev mode
7 | ```yarn build || npm run build``` - Build project
8 | ```../imgs/img.png``` - path for imgs ( SCSS )
9 |
10 | ### Production
11 | Empty vendor bundle size - ~98.9KB min || ~33.9KB GZIP
12 |
13 | Feedback: hello@kenan.agency
14 |
15 | ### TODO
16 |
17 | * [ ] Put loaders into global config
18 | * [ ] Create axios MW for errors
19 | * [ ] Fix postcss config
--------------------------------------------------------------------------------
/configs/workbox.js:
--------------------------------------------------------------------------------
1 | const { GenerateSW } = require('workbox-webpack-plugin');
2 |
3 | const options = {
4 | importWorkboxFrom: 'cdn',
5 | include: [
6 | /\.html$/,
7 | /\.js$/,
8 | /\.json$/,
9 | /\.(png|jpg|svg|ico|woff|woff2)$/
10 | ],
11 | precacheManifestFilename: 'wb-manifest.[manifestHash].js',
12 | cacheId: 'my-app',
13 | };
14 |
15 | module.exports = new GenerateSW(options);
--------------------------------------------------------------------------------
/dist/pwa/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "PWA Template",
3 | "short_name": "PWA",
4 | "start_url": "/",
5 | "lang": "ru-RU",
6 | "display": "fullscreen",
7 | "orientation": "portrait",
8 | "background_color": "#222",
9 | "theme_color": "#222",
10 | "icons": [
11 | {
12 | "src": "../site-icon/app-logo.png",
13 | "sizes": "192x192",
14 | "type": "image/png"
15 | },
16 | {
17 | "src": "../site-icon/app-logo.png",
18 | "sizes": "128x128",
19 | "type": "image/png"
20 | },
21 | {
22 | "src": "../site-icon/app-logo.png",
23 | "sizes": "256x256",
24 | "type": "image/png"
25 | },
26 | {
27 | "src": "../site-icon/app-logo.png",
28 | "sizes": "524x524",
29 | "type": "image/png"
30 | }
31 | ]
32 | }
--------------------------------------------------------------------------------
/dist/site-icon/app-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kayvazov/vue-app-template/cad61b8fae9688f5923fcf292e12bcb5a4a42bfa/dist/site-icon/app-logo.png
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "kenan.agency",
3 | "version": "1.0.0",
4 | "description": "",
5 | "main": "",
6 | "scripts": {
7 | "dev": "webpack-dev-server --progress --port 1488 --hot --host 0.0.0.0 --config webpack.dev.config.js",
8 | "build": "webpack --progress --config webpack.prod.config.js",
9 | "babel-upgrade": "babel-upgrade --write --install"
10 | },
11 | "author": "",
12 | "license": "ISC",
13 | "dependencies": {
14 | "axios": "^0.19.1",
15 | "vue": "^2.5.13",
16 | "vue-loader": "^15.3.0",
17 | "vue-router": "^3.0.1",
18 | "vue-template-compiler": "^2.5.13",
19 | "vuex": "^3.1.2",
20 | "workbox-webpack-plugin": "^4.3.1"
21 | },
22 | "devDependencies": {
23 | "@babel/core": "^7.7.5",
24 | "@babel/plugin-proposal-class-properties": "^7.0.0",
25 | "@babel/plugin-proposal-json-strings": "^7.0.0",
26 | "@babel/plugin-syntax-dynamic-import": "^7.0.0",
27 | "@babel/plugin-syntax-import-meta": "^7.0.0",
28 | "@babel/plugin-transform-runtime": "^7.0.0",
29 | "@babel/preset-env": "^7.0.0",
30 | "@babel/runtime": "^7.7.6",
31 | "autoprefixer": "^9.4.6",
32 | "babel-loader": "^8.0.0",
33 | "css-loader": "^3.3.2",
34 | "css-mqpacker": "^7.0.0",
35 | "fibers": "^4.0.2",
36 | "file-loader": "^1.1.11",
37 | "html-loader": "^0.5.1",
38 | "html-minifier": "^3.5.21",
39 | "html-webpack-plugin": "^3.2.0",
40 | "img-loader": "^2.0.0",
41 | "mini-css-extract-plugin": "^0.7.0",
42 | "postcss-csso": "^3.0.0",
43 | "postcss-flexbugs-fixes": "^4.1.0",
44 | "postcss-loader": "^3.0.0",
45 | "postcss-mq-keyframes": "^0.3.0",
46 | "sass": "^1.23.7",
47 | "sass-loader": "^7.1.0",
48 | "scss-loader": "^0.0.1",
49 | "style-loader": "^0.23.1",
50 | "svg-loader": "^0.0.2",
51 | "template-html-loader": "^1.0.0",
52 | "uglifyjs-webpack-plugin": "^1.1.5",
53 | "url-loader": "^1.1.2",
54 | "webpack": "^4.15.0",
55 | "webpack-bundle-analyzer": "^3.6.0",
56 | "webpack-cli": "^3.1.0",
57 | "webpack-dev-server": "^3.1.5"
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/postcss.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | map: false,
3 | plugins: {
4 | 'postcss-flexbugs-fixes': {},
5 | 'postcss-mq-keyframes': {},
6 | 'css-mqpacker': { sort: true },
7 | 'autoprefixer': {
8 | overrideBrowsersList: [
9 | "> 0.4%",
10 | "not IE 11",
11 | "not OperaMini all",
12 | "not IE_Mob 11",
13 | "edge >= 12",
14 | "chrome >= 30",
15 | "Samsung > 9.2",
16 | "chromeandroid >= 58",
17 | "android >= 10",
18 | "ff >= 60",
19 | "safari >= 11.1",
20 | "ios >= 11.1",
21 | "opera >= 62"
22 | ],
23 | cascade: false,
24 | },
25 | 'postcss-csso': {
26 | restructure: true,
27 | sourceMap: false,
28 | usage: null,
29 | comments: 'none'
30 | }
31 | }
32 | }
--------------------------------------------------------------------------------
/src/icons/technology.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/src/imgs/technology.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kayvazov/vue-app-template/cad61b8fae9688f5923fcf292e12bcb5a4a42bfa/src/imgs/technology.png
--------------------------------------------------------------------------------
/src/js/App.vue:
--------------------------------------------------------------------------------
1 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/js/components/global/Footer.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/js/components/global/Navbar.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/src/js/components/global/NotFound.vue:
--------------------------------------------------------------------------------
1 |
6 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/src/js/components/pages/Main.vue:
--------------------------------------------------------------------------------
1 |
19 |
20 |
21 |
22 |
23 | Vue & PWA template by
24 | Ayvazov Kenan ;3
25 | {{ testStateItem }}
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/src/js/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import router from './routes/route'
3 | import store from './store/index.js'
4 | import asyncData from './store/utils/asyncData'
5 |
6 |
7 | // router hooks
8 | router.beforeResolve(asyncData({ store, router }));
9 |
10 |
11 | // Vue instance
12 | new Vue({
13 | el: "#app",
14 | router,
15 | store,
16 | render: h => h('router-view')
17 | });
--------------------------------------------------------------------------------
/src/js/routes/route.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import VueRouter from 'vue-router'
3 | import App from '../App'
4 | import NotFound from '../components/global/NotFound'
5 | import Main from '../components/pages/Main'
6 |
7 | Vue.use(VueRouter);
8 |
9 | export default new VueRouter({
10 | base: '/',
11 | // remove comments for production tip
12 | // mode: 'history',
13 | routes: [{
14 | path: '/',
15 | component: App,
16 | children: [
17 | {
18 | path: '/',
19 | component: Main
20 | }
21 | ]
22 | },
23 | {
24 | path: '*',
25 | component: NotFound
26 | }
27 | ],
28 | scrollBehavior() {
29 | return {
30 | x: 0,
31 | y: 0
32 | }
33 | }
34 | });
--------------------------------------------------------------------------------
/src/js/store/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import Vuex from 'vuex';
3 | import api from './utils/api';
4 |
5 | // modules
6 | import draft from './modules/draft'
7 |
8 | Vue.use(Vuex);
9 |
10 | export default new Vuex.Store({
11 | modules: {
12 | draft
13 | }
14 | })
--------------------------------------------------------------------------------
/src/js/store/modules/draft.js:
--------------------------------------------------------------------------------
1 | export default {
2 | state: {
3 | test: 'correct'
4 | },
5 | actions: {},
6 | mutations: {}
7 | // ...
8 | }
--------------------------------------------------------------------------------
/src/js/store/utils/api.js:
--------------------------------------------------------------------------------
1 | import axios from "axios";
2 |
3 | export default axios.create({
4 | baseURL: 'https://your-api-endpoint.com:3000',
5 | });
6 |
--------------------------------------------------------------------------------
/src/js/store/utils/asyncData.js:
--------------------------------------------------------------------------------
1 | export default ({ store, router }) => async (to, from, next) => {
2 | const matched = router.getMatchedComponents(to);
3 | const prevMatched = router.getMatchedComponents(from);
4 | let diffed = false;
5 |
6 | const activated = matched.filter((c, i) => {
7 | const isActivated = diffed || (diffed = (prevMatched[i] !== c));
8 | return isActivated;
9 | });
10 |
11 | if (!activated.length) {
12 | // push last match for loading asyncData
13 | activated.push(matched[matched.length - 1]);
14 | }
15 |
16 | const asyncDataHooks = [router.app.$options, ...activated]
17 | .filter((_) => _)
18 | .map((c) => c.asyncData)
19 | .filter((_) => _);
20 |
21 | if (!asyncDataHooks.length) {
22 | next();
23 | return;
24 | }
25 |
26 | try {
27 | const hooks = asyncDataHooks
28 | .map((hook) => hook({ store, router, route: to }))
29 | .filter((_) => _);
30 |
31 | await Promise.all(hooks);
32 | next();
33 | } catch (error) {
34 | if (process.env.NODE_ENV !== 'production') {
35 | console.warn('Error while asyncData:');
36 | console.error(error);
37 | }
38 |
39 | next();
40 | }
41 | };
42 |
--------------------------------------------------------------------------------
/src/scss/components/_global.scss:
--------------------------------------------------------------------------------
1 | html,
2 | body {
3 | width: 100%;
4 | height: 100%;
5 | margin: 0;
6 | font-size: 14px;
7 | box-sizing: border-box;
8 | color: #fff;
9 | font-family: -apple-system, BlinkMacSystemFont, sans-serif !important;
10 | -webkit-font-smoothing: antialiased;
11 | -moz-osx-font-smoothing: grayscale;
12 | scroll-behavior: smooth;
13 | -webkit-overflow-scrolling: touch;
14 | }
15 |
16 | ul {
17 | padding: 0;
18 | margin: 0;
19 | }
20 |
21 | ul li {
22 | list-style-type: none;
23 | }
24 |
25 | a {
26 | text-decoration: none;
27 | }
28 |
29 | input,
30 | button,
31 | textarea,
32 | select,
33 | option {
34 | &:focus {
35 | outline: none;
36 | }
37 | }
38 |
39 | input,
40 | button,
41 | textarea {
42 | border-radius: 0;
43 | -webkit-appearance: none;
44 | -moz-appearance: none;
45 |
46 | &::-ms-expand {
47 | display: none;
48 | }
49 | }
50 |
51 | // Demo styles
52 | body {
53 | display: flex;
54 | justify-content: center;
55 | align-items: center;
56 | }
57 |
58 | p {
59 | color: #000;
60 | font-size: 24px;
61 | text-decoration: underline;
62 | }
63 |
64 | // Example
65 | .png {
66 | width: 120px;
67 | height: 120px;
68 | background: url('../imgs/technology.png') no-repeat center / cover;
69 | }
70 |
--------------------------------------------------------------------------------
/src/scss/components/freq/_frequest.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kayvazov/vue-app-template/cad61b8fae9688f5923fcf292e12bcb5a4a42bfa/src/scss/components/freq/_frequest.scss
--------------------------------------------------------------------------------
/src/scss/components/utils/_fonts.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kayvazov/vue-app-template/cad61b8fae9688f5923fcf292e12bcb5a4a42bfa/src/scss/components/utils/_fonts.scss
--------------------------------------------------------------------------------
/src/scss/components/utils/_media.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kayvazov/vue-app-template/cad61b8fae9688f5923fcf292e12bcb5a4a42bfa/src/scss/components/utils/_media.scss
--------------------------------------------------------------------------------
/src/scss/components/utils/_variables.scss:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/kayvazov/vue-app-template/cad61b8fae9688f5923fcf292e12bcb5a4a42bfa/src/scss/components/utils/_variables.scss
--------------------------------------------------------------------------------
/src/scss/components/vendor/_bootstrap-grid.scss:
--------------------------------------------------------------------------------
1 | html{-webkit-box-sizing:border-box;box-sizing:border-box;-ms-overflow-style:scrollbar}*,::after,::before{-webkit-box-sizing:inherit;box-sizing:inherit}.container{position:relative;margin-left:auto;margin-right:auto;padding-right:10px;padding-left:10px}@media (min-width:576px){.container{padding-right:10px;padding-left:10px}}@media (min-width:768px){.container{padding-right:10px;padding-left:10px}}@media (min-width:992px){.container{padding-right:10px;padding-left:10px}}@media (min-width:1200px){.container{padding-right:10px;padding-left:10px}}@media (min-width:576px){.container{width:540px;max-width:100%}}@media (min-width:768px){.container{width:720px;max-width:100%}}@media (min-width:992px){.container{width:960px;max-width:100%}}@media (min-width:1200px){.container{width:1280px;max-width:100%}}.container-fluid{position:relative;margin-left:auto;margin-right:auto;padding-right:10px;padding-left:10px}@media (min-width:576px){.container-fluid{padding-right:10px;padding-left:10px}}@media (min-width:768px){.container-fluid{padding-right:10px;padding-left:10px}}@media (min-width:992px){.container-fluid{padding-right:10px;padding-left:10px}}@media (min-width:1200px){.container-fluid{padding-right:10px;padding-left:10px}}.row{display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-flex-wrap:wrap;-ms-flex-wrap:wrap;flex-wrap:wrap;margin-right:-10px;margin-left:-10px}@media (min-width:576px){.row{margin-right:-10px;margin-left:-10px}}@media (min-width:768px){.row{margin-right:-10px;margin-left:-10px}}@media (min-width:992px){.row{margin-right:-10px;margin-left:-10px}}@media (min-width:1200px){.row{margin-right:-10px;margin-left:-10px}}.no-gutters{margin-right:0;margin-left:0}.no-gutters>.col,.no-gutters>[class*=col-]{padding-right:0;padding-left:0}.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9{position:relative;width:100%;min-height:1px;padding-right:10px;padding-left:10px}@media (min-width:576px){.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9{padding-right:10px;padding-left:10px}}@media (min-width:768px){.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9{padding-right:10px;padding-left:10px}}@media (min-width:992px){.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9{padding-right:10px;padding-left:10px}}@media (min-width:1200px){.col,.col-1,.col-10,.col-11,.col-12,.col-2,.col-3,.col-4,.col-5,.col-6,.col-7,.col-8,.col-9,.col-lg,.col-lg-1,.col-lg-10,.col-lg-11,.col-lg-12,.col-lg-2,.col-lg-3,.col-lg-4,.col-lg-5,.col-lg-6,.col-lg-7,.col-lg-8,.col-lg-9,.col-md,.col-md-1,.col-md-10,.col-md-11,.col-md-12,.col-md-2,.col-md-3,.col-md-4,.col-md-5,.col-md-6,.col-md-7,.col-md-8,.col-md-9,.col-sm,.col-sm-1,.col-sm-10,.col-sm-11,.col-sm-12,.col-sm-2,.col-sm-3,.col-sm-4,.col-sm-5,.col-sm-6,.col-sm-7,.col-sm-8,.col-sm-9,.col-xl,.col-xl-1,.col-xl-10,.col-xl-11,.col-xl-12,.col-xl-2,.col-xl-3,.col-xl-4,.col-xl-5,.col-xl-6,.col-xl-7,.col-xl-8,.col-xl-9{padding-right:10px;padding-left:10px}}.col{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-auto{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.col-1{-webkit-box-flex:0;-webkit-flex:0 0 8.333333%;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-2{-webkit-box-flex:0;-webkit-flex:0 0 16.666667%;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-3{-webkit-box-flex:0;-webkit-flex:0 0 25%;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-4{-webkit-box-flex:0;-webkit-flex:0 0 33.333333%;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-5{-webkit-box-flex:0;-webkit-flex:0 0 41.666667%;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-6{-webkit-box-flex:0;-webkit-flex:0 0 50%;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-7{-webkit-box-flex:0;-webkit-flex:0 0 58.333333%;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-8{-webkit-box-flex:0;-webkit-flex:0 0 66.666667%;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-9{-webkit-box-flex:0;-webkit-flex:0 0 75%;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-10{-webkit-box-flex:0;-webkit-flex:0 0 83.333333%;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-11{-webkit-box-flex:0;-webkit-flex:0 0 91.666667%;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-12{-webkit-box-flex:0;-webkit-flex:0 0 100%;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.pull-0{right:auto}.pull-1{right:8.333333%}.pull-2{right:16.666667%}.pull-3{right:25%}.pull-4{right:33.333333%}.pull-5{right:41.666667%}.pull-6{right:50%}.pull-7{right:58.333333%}.pull-8{right:66.666667%}.pull-9{right:75%}.pull-10{right:83.333333%}.pull-11{right:91.666667%}.pull-12{right:100%}.push-0{left:auto}.push-1{left:8.333333%}.push-2{left:16.666667%}.push-3{left:25%}.push-4{left:33.333333%}.push-5{left:41.666667%}.push-6{left:50%}.push-7{left:58.333333%}.push-8{left:66.666667%}.push-9{left:75%}.push-10{left:83.333333%}.push-11{left:91.666667%}.push-12{left:100%}.offset-1{margin-left:8.333333%}.offset-2{margin-left:16.666667%}.offset-3{margin-left:25%}.offset-4{margin-left:33.333333%}.offset-5{margin-left:41.666667%}.offset-6{margin-left:50%}.offset-7{margin-left:58.333333%}.offset-8{margin-left:66.666667%}.offset-9{margin-left:75%}.offset-10{margin-left:83.333333%}.offset-11{margin-left:91.666667%}@media (min-width:576px){.col-sm{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-sm-auto{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.col-sm-1{-webkit-box-flex:0;-webkit-flex:0 0 8.333333%;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-sm-2{-webkit-box-flex:0;-webkit-flex:0 0 16.666667%;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-sm-3{-webkit-box-flex:0;-webkit-flex:0 0 25%;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-sm-4{-webkit-box-flex:0;-webkit-flex:0 0 33.333333%;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-sm-5{-webkit-box-flex:0;-webkit-flex:0 0 41.666667%;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-sm-6{-webkit-box-flex:0;-webkit-flex:0 0 50%;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-sm-7{-webkit-box-flex:0;-webkit-flex:0 0 58.333333%;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-sm-8{-webkit-box-flex:0;-webkit-flex:0 0 66.666667%;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-sm-9{-webkit-box-flex:0;-webkit-flex:0 0 75%;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-sm-10{-webkit-box-flex:0;-webkit-flex:0 0 83.333333%;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-sm-11{-webkit-box-flex:0;-webkit-flex:0 0 91.666667%;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-sm-12{-webkit-box-flex:0;-webkit-flex:0 0 100%;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.pull-sm-0{right:auto}.pull-sm-1{right:8.333333%}.pull-sm-2{right:16.666667%}.pull-sm-3{right:25%}.pull-sm-4{right:33.333333%}.pull-sm-5{right:41.666667%}.pull-sm-6{right:50%}.pull-sm-7{right:58.333333%}.pull-sm-8{right:66.666667%}.pull-sm-9{right:75%}.pull-sm-10{right:83.333333%}.pull-sm-11{right:91.666667%}.pull-sm-12{right:100%}.push-sm-0{left:auto}.push-sm-1{left:8.333333%}.push-sm-2{left:16.666667%}.push-sm-3{left:25%}.push-sm-4{left:33.333333%}.push-sm-5{left:41.666667%}.push-sm-6{left:50%}.push-sm-7{left:58.333333%}.push-sm-8{left:66.666667%}.push-sm-9{left:75%}.push-sm-10{left:83.333333%}.push-sm-11{left:91.666667%}.push-sm-12{left:100%}.offset-sm-0{margin-left:0}.offset-sm-1{margin-left:8.333333%}.offset-sm-2{margin-left:16.666667%}.offset-sm-3{margin-left:25%}.offset-sm-4{margin-left:33.333333%}.offset-sm-5{margin-left:41.666667%}.offset-sm-6{margin-left:50%}.offset-sm-7{margin-left:58.333333%}.offset-sm-8{margin-left:66.666667%}.offset-sm-9{margin-left:75%}.offset-sm-10{margin-left:83.333333%}.offset-sm-11{margin-left:91.666667%}}@media (min-width:768px){.col-md{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-md-auto{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.col-md-1{-webkit-box-flex:0;-webkit-flex:0 0 8.333333%;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-md-2{-webkit-box-flex:0;-webkit-flex:0 0 16.666667%;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-md-3{-webkit-box-flex:0;-webkit-flex:0 0 25%;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-md-4{-webkit-box-flex:0;-webkit-flex:0 0 33.333333%;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-md-5{-webkit-box-flex:0;-webkit-flex:0 0 41.666667%;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-md-6{-webkit-box-flex:0;-webkit-flex:0 0 50%;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-md-7{-webkit-box-flex:0;-webkit-flex:0 0 58.333333%;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-md-8{-webkit-box-flex:0;-webkit-flex:0 0 66.666667%;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-md-9{-webkit-box-flex:0;-webkit-flex:0 0 75%;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-md-10{-webkit-box-flex:0;-webkit-flex:0 0 83.333333%;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-md-11{-webkit-box-flex:0;-webkit-flex:0 0 91.666667%;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-md-12{-webkit-box-flex:0;-webkit-flex:0 0 100%;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.pull-md-0{right:auto}.pull-md-1{right:8.333333%}.pull-md-2{right:16.666667%}.pull-md-3{right:25%}.pull-md-4{right:33.333333%}.pull-md-5{right:41.666667%}.pull-md-6{right:50%}.pull-md-7{right:58.333333%}.pull-md-8{right:66.666667%}.pull-md-9{right:75%}.pull-md-10{right:83.333333%}.pull-md-11{right:91.666667%}.pull-md-12{right:100%}.push-md-0{left:auto}.push-md-1{left:8.333333%}.push-md-2{left:16.666667%}.push-md-3{left:25%}.push-md-4{left:33.333333%}.push-md-5{left:41.666667%}.push-md-6{left:50%}.push-md-7{left:58.333333%}.push-md-8{left:66.666667%}.push-md-9{left:75%}.push-md-10{left:83.333333%}.push-md-11{left:91.666667%}.push-md-12{left:100%}.offset-md-0{margin-left:0}.offset-md-1{margin-left:8.333333%}.offset-md-2{margin-left:16.666667%}.offset-md-3{margin-left:25%}.offset-md-4{margin-left:33.333333%}.offset-md-5{margin-left:41.666667%}.offset-md-6{margin-left:50%}.offset-md-7{margin-left:58.333333%}.offset-md-8{margin-left:66.666667%}.offset-md-9{margin-left:75%}.offset-md-10{margin-left:83.333333%}.offset-md-11{margin-left:91.666667%}}@media (min-width:992px){.col-lg{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-lg-auto{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.col-lg-1{-webkit-box-flex:0;-webkit-flex:0 0 8.333333%;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-lg-2{-webkit-box-flex:0;-webkit-flex:0 0 16.666667%;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-lg-3{-webkit-box-flex:0;-webkit-flex:0 0 25%;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-lg-4{-webkit-box-flex:0;-webkit-flex:0 0 33.333333%;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-lg-5{-webkit-box-flex:0;-webkit-flex:0 0 41.666667%;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-lg-6{-webkit-box-flex:0;-webkit-flex:0 0 50%;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-lg-7{-webkit-box-flex:0;-webkit-flex:0 0 58.333333%;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-lg-8{-webkit-box-flex:0;-webkit-flex:0 0 66.666667%;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-lg-9{-webkit-box-flex:0;-webkit-flex:0 0 75%;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-lg-10{-webkit-box-flex:0;-webkit-flex:0 0 83.333333%;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-lg-11{-webkit-box-flex:0;-webkit-flex:0 0 91.666667%;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-lg-12{-webkit-box-flex:0;-webkit-flex:0 0 100%;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.pull-lg-0{right:auto}.pull-lg-1{right:8.333333%}.pull-lg-2{right:16.666667%}.pull-lg-3{right:25%}.pull-lg-4{right:33.333333%}.pull-lg-5{right:41.666667%}.pull-lg-6{right:50%}.pull-lg-7{right:58.333333%}.pull-lg-8{right:66.666667%}.pull-lg-9{right:75%}.pull-lg-10{right:83.333333%}.pull-lg-11{right:91.666667%}.pull-lg-12{right:100%}.push-lg-0{left:auto}.push-lg-1{left:8.333333%}.push-lg-2{left:16.666667%}.push-lg-3{left:25%}.push-lg-4{left:33.333333%}.push-lg-5{left:41.666667%}.push-lg-6{left:50%}.push-lg-7{left:58.333333%}.push-lg-8{left:66.666667%}.push-lg-9{left:75%}.push-lg-10{left:83.333333%}.push-lg-11{left:91.666667%}.push-lg-12{left:100%}.offset-lg-0{margin-left:0}.offset-lg-1{margin-left:8.333333%}.offset-lg-2{margin-left:16.666667%}.offset-lg-3{margin-left:25%}.offset-lg-4{margin-left:33.333333%}.offset-lg-5{margin-left:41.666667%}.offset-lg-6{margin-left:50%}.offset-lg-7{margin-left:58.333333%}.offset-lg-8{margin-left:66.666667%}.offset-lg-9{margin-left:75%}.offset-lg-10{margin-left:83.333333%}.offset-lg-11{margin-left:91.666667%}}@media (min-width:1200px){.col-xl{-webkit-flex-basis:0;-ms-flex-preferred-size:0;flex-basis:0;-webkit-box-flex:1;-webkit-flex-grow:1;-ms-flex-positive:1;flex-grow:1;max-width:100%}.col-xl-auto{-webkit-box-flex:0;-webkit-flex:0 0 auto;-ms-flex:0 0 auto;flex:0 0 auto;width:auto}.col-xl-1{-webkit-box-flex:0;-webkit-flex:0 0 8.333333%;-ms-flex:0 0 8.333333%;flex:0 0 8.333333%;max-width:8.333333%}.col-xl-2{-webkit-box-flex:0;-webkit-flex:0 0 16.666667%;-ms-flex:0 0 16.666667%;flex:0 0 16.666667%;max-width:16.666667%}.col-xl-3{-webkit-box-flex:0;-webkit-flex:0 0 25%;-ms-flex:0 0 25%;flex:0 0 25%;max-width:25%}.col-xl-4{-webkit-box-flex:0;-webkit-flex:0 0 33.333333%;-ms-flex:0 0 33.333333%;flex:0 0 33.333333%;max-width:33.333333%}.col-xl-5{-webkit-box-flex:0;-webkit-flex:0 0 41.666667%;-ms-flex:0 0 41.666667%;flex:0 0 41.666667%;max-width:41.666667%}.col-xl-6{-webkit-box-flex:0;-webkit-flex:0 0 50%;-ms-flex:0 0 50%;flex:0 0 50%;max-width:50%}.col-xl-7{-webkit-box-flex:0;-webkit-flex:0 0 58.333333%;-ms-flex:0 0 58.333333%;flex:0 0 58.333333%;max-width:58.333333%}.col-xl-8{-webkit-box-flex:0;-webkit-flex:0 0 66.666667%;-ms-flex:0 0 66.666667%;flex:0 0 66.666667%;max-width:66.666667%}.col-xl-9{-webkit-box-flex:0;-webkit-flex:0 0 75%;-ms-flex:0 0 75%;flex:0 0 75%;max-width:75%}.col-xl-10{-webkit-box-flex:0;-webkit-flex:0 0 83.333333%;-ms-flex:0 0 83.333333%;flex:0 0 83.333333%;max-width:83.333333%}.col-xl-11{-webkit-box-flex:0;-webkit-flex:0 0 91.666667%;-ms-flex:0 0 91.666667%;flex:0 0 91.666667%;max-width:91.666667%}.col-xl-12{-webkit-box-flex:0;-webkit-flex:0 0 100%;-ms-flex:0 0 100%;flex:0 0 100%;max-width:100%}.pull-xl-0{right:auto}.pull-xl-1{right:8.333333%}.pull-xl-2{right:16.666667%}.pull-xl-3{right:25%}.pull-xl-4{right:33.333333%}.pull-xl-5{right:41.666667%}.pull-xl-6{right:50%}.pull-xl-7{right:58.333333%}.pull-xl-8{right:66.666667%}.pull-xl-9{right:75%}.pull-xl-10{right:83.333333%}.pull-xl-11{right:91.666667%}.pull-xl-12{right:100%}.push-xl-0{left:auto}.push-xl-1{left:8.333333%}.push-xl-2{left:16.666667%}.push-xl-3{left:25%}.push-xl-4{left:33.333333%}.push-xl-5{left:41.666667%}.push-xl-6{left:50%}.push-xl-7{left:58.333333%}.push-xl-8{left:66.666667%}.push-xl-9{left:75%}.push-xl-10{left:83.333333%}.push-xl-11{left:91.666667%}.push-xl-12{left:100%}.offset-xl-0{margin-left:0}.offset-xl-1{margin-left:8.333333%}.offset-xl-2{margin-left:16.666667%}.offset-xl-3{margin-left:25%}.offset-xl-4{margin-left:33.333333%}.offset-xl-5{margin-left:41.666667%}.offset-xl-6{margin-left:50%}.offset-xl-7{margin-left:58.333333%}.offset-xl-8{margin-left:66.666667%}.offset-xl-9{margin-left:75%}.offset-xl-10{margin-left:83.333333%}.offset-xl-11{margin-left:91.666667%}}
2 |
--------------------------------------------------------------------------------
/src/scss/index.scss:
--------------------------------------------------------------------------------
1 | // Utils
2 | @import "components/utils/fonts";
3 | @import "components/utils/variables";
4 | // Bootstrap ( can delete if you dont use )
5 | @import "components/vendor/bootstrap-grid";
6 | // Frequest
7 | @import "components/freq/frequest";
8 | // Global styles
9 | @import "components/global";
10 | // Media rules
11 | @import "components/utils/media";
--------------------------------------------------------------------------------
/src/template/index.template.ejs:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | <%= htmlWebpackPlugin.options.meta.title %>
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
56 |
57 |
63 |
64 |
74 |
75 |
76 |
77 |
--------------------------------------------------------------------------------
/webpack.dev.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const webpack = require('webpack');
3 | const VueLoaderPlugin = require('vue-loader/lib/plugin');
4 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
5 | const HtmlWebpackPlugin = require('html-webpack-plugin');
6 | const TerserJSPlugin = require('terser-webpack-plugin');
7 | const MiniCssExtractPlugin = require('mini-css-extract-plugin');
8 | // config parts
9 | const Workbox = require('./configs/workbox.js');
10 |
11 | module.exports = {
12 | entry: [
13 | "./src/js/index.js",
14 | './src/scss/index.scss'
15 | ],
16 | output: {
17 | path: path.resolve(__dirname, 'dist'),
18 | filename: 'js/[name].js'
19 | },
20 | devServer: {
21 | compress: true,
22 | historyApiFallback: true,
23 | //https: true for https
24 | },
25 | optimization: {
26 | minimizer: [new TerserJSPlugin({})],
27 | splitChunks: {
28 | cacheGroups: {
29 | // js splitting
30 | vendor: {
31 | name: 'vendor',
32 | test: /node_modules/,
33 | chunks: 'all',
34 | enforce: true
35 | },
36 | global: {
37 | name: 'global',
38 | test: /global/,
39 | chunks: 'all',
40 | enforce: true
41 | },
42 | pages: {
43 | name: 'pages',
44 | test: /pages/,
45 | chunks: 'all',
46 | enforce: true
47 | },
48 | // css splitting
49 | // future :)
50 | }
51 | }
52 | },
53 | mode: 'development',
54 | module: {
55 | rules: [
56 | {
57 | test: /\.vue$/,
58 | exclude: /node_modules/,
59 | loader: 'vue-loader',
60 | options: {
61 | loaders: {
62 | css: ''
63 | }
64 | }
65 | },
66 | {
67 | test: /\.css$/,
68 | use: ['style-loader', 'css-loader']
69 | },
70 | {
71 | test: /\.(sa|sc|c)ss$/,
72 | use: [
73 | {
74 | loader: MiniCssExtractPlugin.loader,
75 | options: {
76 | publicPath: '../',
77 | hmr: true,
78 | // force reload
79 | reloadAll: true,
80 | }
81 | },
82 | // работаем с @import и url()
83 | {
84 | loader: 'css-loader'
85 | },
86 | // далее, по .css файлу проходиться postcss-loader да бы, проставить все нужные полифиллы и префиксы к свойствам
87 | 'postcss-loader',
88 | // в начале sass-loader переводить .scss файл в .css
89 | {
90 | loader: 'sass-loader',
91 | options: {
92 | implementation: require('sass'),
93 | sassOptions: {
94 | fiber: require('fibers'),
95 | indentedSyntax: true // optional
96 | },
97 | }
98 | }
99 | ]
100 | },
101 | {
102 | test: /\.js?$/,
103 | exclude: /node_modules/,
104 | loader: 'babel-loader'
105 | },
106 | {
107 | test: /\.(woff|woff2)$/,
108 | loader: 'url-loader',
109 | options: {
110 | limit: 1,
111 | publicPath: 'fonts',
112 | name: '[name].[sha1:hash:base64:5].[ext]'
113 | },
114 | },
115 | {
116 | test: /\.(png|jpg)$/,
117 | loader: 'file-loader',
118 | options: {
119 | outputPath: 'dist/imgs',
120 | name: '[name].[ext]'
121 | },
122 | },
123 | {
124 | test: /\.(svg)$/,
125 | loader: 'url-loader',
126 | options: {
127 | limit: 1,
128 | name: 'dist/icons/[name].[sha1:hash:base64:5].[ext]'
129 | },
130 | },
131 | ]
132 | },
133 | plugins: [
134 | new MiniCssExtractPlugin({
135 | filename: 'css/main.[hash:4].css',
136 | chunkFilename: 'css/[name].[hash:4].css'
137 | }),
138 | new VueLoaderPlugin(),
139 | new webpack.NoEmitOnErrorsPlugin(),
140 | new webpack.HotModuleReplacementPlugin(),
141 | new HtmlWebpackPlugin({
142 | filename: './index.html',
143 | template: './src/template/index.template.ejs',
144 | children: false,
145 | // template info
146 | manifest: './dist/pwa/manifest.json',
147 | icon: {
148 | shortcut: './dist/site-icon/app-logo.png',
149 | apple: {
150 | '57x57': './dist/site-icon/app-logo.png',
151 | '60x60': './dist/site-icon/app-logo.png',
152 | '72x72': './dist/site-icon/app-logo.png',
153 | '76x76': './dist/site-icon/app-logo.png',
154 | '114x114': './dist/site-icon/app-logo.png',
155 | '120x120': './dist/site-icon/app-logo.png',
156 | '144x144': './dist/site-icon/app-logo.png',
157 | '152x152': './dist/site-icon/app-logo.png',
158 | '180x180': './dist/site-icon/app-logo.png',
159 | }
160 | },
161 | meta: {
162 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur at blanditiis consectetur cupiditate dignissimos esse, fugiat illum laudantium nihil, nisi numquam obcaecati officiis optio placeat, quas quasi sequi soluta voluptatibus?',
163 | title: 'Vue & PWA app',
164 | url: '//your-site-link.com'
165 | }
166 | }),
167 | new webpack.ProvidePlugin({
168 | $: "jquery",
169 | jQuery: "jquery",
170 | "window.jQuery": "jquery"
171 | }),
172 | new UglifyJsPlugin({
173 | uglifyOptions: {
174 | ie8: false,
175 | ecma: 8,
176 | output: {
177 | comments: false,
178 | beautify: false
179 | }
180 | }
181 | }),
182 | //Workbox
183 | ],
184 | resolve: {
185 | extensions: [".js", ".vue", ".json"],
186 | alias: {
187 | vue: 'vue/dist/vue.runtime.min.js',
188 | 'vue-router': 'vue-router/dist/vue-router.min.js',
189 | 'vuex': 'vuex/dist/vuex.min.js',
190 | 'images': path.resolve(__dirname, './src/imgs'),
191 | 'icons': path.resolve(__dirname, './src/icons')
192 | }
193 | },
194 | node: {
195 | module: 'empty',
196 | fsevents: 'empty',
197 | net: 'empty',
198 | tls: 'empty'
199 | }
200 | };
201 |
--------------------------------------------------------------------------------
/webpack.prod.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 | const webpack = require('webpack');
3 | const VueLoaderPlugin = require('vue-loader/lib/plugin');
4 | const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
5 | const HtmlWebpackPlugin = require('html-webpack-plugin');
6 | const TerserJSPlugin = require('terser-webpack-plugin');
7 | const MiniCssExtractPlugin = require('mini-css-extract-plugin');
8 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
9 | // config parts
10 | const Workbox = require('./configs/workbox.js');
11 |
12 | const PUBLIC_PATH = 'URL';
13 |
14 | module.exports = {
15 | entry: [
16 | "./src/js/index.js",
17 | './src/scss/index.scss'
18 | ],
19 | output: {
20 | path: path.resolve(__dirname, './dist'),
21 | filename: "js/[name].[hash:5].js",
22 | },
23 | optimization: {
24 | minimizer: [new TerserJSPlugin({})],
25 | splitChunks: {
26 | cacheGroups: {
27 | vendor: {
28 | name: 'vendor',
29 | test: /node_modules/,
30 | chunks: 'all',
31 | enforce: true
32 | },
33 | global: {
34 | name: 'global',
35 | test: /global/,
36 | chunks: 'all',
37 | enforce: true
38 | },
39 | pages: {
40 | name: 'pages',
41 | test: /pages/,
42 | chunks: 'all',
43 | enforce: true
44 | }
45 | }
46 | }
47 | },
48 | mode: 'production',
49 | module: {
50 | rules: [
51 | {
52 | test: /\.vue$/,
53 | exclude: /node_modules/,
54 | loader: 'vue-loader',
55 | },
56 | {
57 | test: /\.css$/i,
58 | use: [
59 | {
60 | loader: MiniCssExtractPlugin.loader,
61 | options: {
62 | publicPath: '../',
63 | }
64 | },
65 | 'css-loader'
66 | ]
67 | },
68 | {
69 | test: /\.s(c|a)ss$/,
70 | use: [
71 | {
72 | loader: MiniCssExtractPlugin.loader,
73 | options: {
74 | publicPath: '../',
75 | }
76 | },
77 | // работаем с @import и url()
78 | {
79 | loader: 'css-loader',
80 | options: {
81 | modules: 'global'
82 | }
83 | },
84 | // далее, по .css файлу проходиться postcss-loader да бы, проставить все нужные полифиллы и префиксы к свойствам
85 | 'postcss-loader',
86 | // в начале sass-loader переводить .scss файл в .css
87 | {
88 | loader: 'sass-loader',
89 | options: {
90 | implementation: require('sass'),
91 | sassOptions: {
92 | fiber: require('fibers'),
93 | indentedSyntax: true // optional
94 | },
95 | }
96 | }
97 | ]
98 | },
99 | {
100 | test: /\.js?$/,
101 | exclude: /node_modules/,
102 | loader: 'babel-loader'
103 | },
104 | // fonts
105 | {
106 | test: /\.(woff|woff2)$/,
107 | loader: 'url-loader',
108 | options: {
109 | limit: 1,
110 | publicPath: 'fonts',
111 | outputPath: 'fonts',
112 | name: '[name].[sha1:hash:base64:5].[ext]'
113 | },
114 | },
115 | {
116 | test: /\.(svg)$/,
117 | loader: 'url-loader',
118 | options: {
119 | limit: 1,
120 | publicPath: 'dist/icons',
121 | outputPath: 'icons',
122 | name: '[name].[sha1:hash:base64:5].[ext]'
123 | },
124 | },
125 | {
126 | test: /\.(png|jpg)$/,
127 | loader: 'url-loader',
128 | options: {
129 | limit: 1,
130 | publicPath: 'dist/imgs',
131 | outputPath: 'imgs',
132 | name: '[name].[sha1:hash:base64:5].[ext]'
133 | },
134 | }
135 | ]
136 | },
137 | plugins: [
138 | new MiniCssExtractPlugin({
139 | filename: 'css/main.[hash:4].css',
140 | }),
141 |
142 | new VueLoaderPlugin(),
143 | new webpack.NoEmitOnErrorsPlugin(),
144 | new HtmlWebpackPlugin({
145 | minify: {
146 | removeComments: true,
147 | collapseWhitespace: true
148 | },
149 | filename: '../index.html',
150 | template: './src/template/index.template.ejs',
151 | children: false,
152 | // template info
153 | manifest: './dist/pwa/manifest.json',
154 | icon: {
155 | shortcut: './dist/site-icon/app-logo.png',
156 | apple: {
157 | '57x57': './dist/site-icon/app-logo.png',
158 | '60x60': './dist/site-icon/app-logo.png',
159 | '72x72': './dist/site-icon/app-logo.png',
160 | '76x76': './dist/site-icon/app-logo.png',
161 | '114x114': './dist/site-icon/app-logo.png',
162 | '120x120': './dist/site-icon/app-logo.png',
163 | '144x144': './dist/site-icon/app-logo.png',
164 | '152x152': './dist/site-icon/app-logo.png',
165 | '180x180': './dist/site-icon/app-logo.png',
166 | }
167 | },
168 | meta: {
169 | description: 'Lorem ipsum dolor sit amet, consectetur adipisicing elit. Aspernatur at blanditiis consectetur cupiditate dignissimos esse, fugiat illum laudantium nihil, nisi numquam obcaecati officiis optio placeat, quas quasi sequi soluta voluptatibus?',
170 | title: 'Vue & PWA app',
171 | url: '//your-site-link.com'
172 | }
173 | }),
174 | new webpack.ProvidePlugin({
175 | $: "jquery",
176 | jQuery: "jquery",
177 | "window.jQuery": "jquery"
178 | }),
179 | new UglifyJsPlugin({
180 | uglifyOptions: {
181 | ie8: false,
182 | ecma: 8,
183 | output: {
184 | comments: false,
185 | beautify: false
186 | }
187 | }
188 | }),
189 | //new BundleAnalyzerPlugin(),
190 | //Workbox
191 | ],
192 | resolve: {
193 | extensions: [".js", ".vue", ".json"],
194 | alias: {
195 | vue: 'vue/dist/vue.runtime.min.js',
196 | 'vue-router': 'vue-router/dist/vue-router.min.js',
197 | 'vuex': 'vuex/dist/vuex.min.js',
198 | 'images': path.resolve(__dirname, './src/imgs'),
199 | 'icons': path.resolve(__dirname, './src/icons')
200 | }
201 | },
202 | node: {
203 | module: 'empty',
204 | fsevents: 'empty',
205 | net: 'empty',
206 | tls: 'empty',
207 | setImmediate: false,
208 | process: false
209 | }
210 | };
211 |
--------------------------------------------------------------------------------