├── .babelrc ├── .eslintrc.json ├── .gitignore ├── LICENSE ├── README.md ├── config ├── env │ ├── dev.env.js │ ├── prod.env.js │ └── staging.env.js ├── helpers.js ├── webpack.config.common.js ├── webpack.config.dev.js └── webpack.config.prod.js ├── index.html ├── package.json ├── src ├── App.vue ├── components │ ├── AppHome.vue │ └── AppMedium.vue ├── main.js └── routes.js └── webpack.config.js /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | [ 4 | "@babel/preset-env", 5 | { 6 | "modules": false, 7 | "targets": { 8 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8", "ie >= 11"] 9 | } 10 | } 11 | ] 12 | ], 13 | "plugins": [ 14 | "@babel/plugin-syntax-dynamic-import" 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "browser": true, 4 | "commonjs": true, 5 | "es6": true, 6 | "node": true 7 | }, 8 | "parserOptions": { 9 | "parser": "babel-eslint", 10 | "sourceType": "module", 11 | "ecmaVersion": 2018 12 | }, 13 | "extends": [ 14 | "eslint:recommended", 15 | "plugin:vue/base", 16 | "plugin:vue/essential", 17 | "plugin:vue/strongly-recommended", 18 | "plugin:vue/recommended" 19 | ], 20 | "rules": { 21 | "array-bracket-spacing": [ "error", "always" ], 22 | "arrow-spacing": "error", 23 | "constructor-super": "error", 24 | "curly": "error", 25 | "indent": ["error", 4, { "SwitchCase": 1 }], 26 | "keyword-spacing": "error", 27 | "no-console": 0, 28 | "no-const-assign": "error", 29 | "no-debugger": 0, 30 | "no-duplicate-imports": "error", 31 | "no-multiple-empty-lines": [ 2, { "max": 2, "maxEOF": 1 } ], 32 | "no-this-before-super": "error", 33 | "no-unreachable": "error", 34 | "no-unused-vars": 0, 35 | "no-useless-escape": 0, 36 | "no-var": "error", 37 | "object-curly-spacing": [ "error", "always" ], 38 | "one-var": ["error", { "var": "never", "let": "never", "const": "never" }], 39 | "prefer-arrow-callback": "error", 40 | "prefer-const": "error", 41 | "quotes": [ "error", "single", { "allowTemplateLiterals": true } ], 42 | "semi": ["error", "always"], 43 | "sort-imports": ["error", { "ignoreDeclarationSort": true }], 44 | "space-before-function-paren": "error", 45 | "valid-typeof": "error", 46 | "vue/component-name-in-template-casing": ["error", "PascalCase", 47 | { 48 | "ignores": [ 49 | "router-link", 50 | "router-view", 51 | "transition" 52 | ] 53 | } 54 | ] 55 | }, 56 | "plugins": [ 57 | "vue" 58 | ] 59 | } 60 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea/ 2 | .vscode/ 3 | node_modules/ 4 | dist/ 5 | npm-debug.log 6 | package-lock.json 7 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Samuel Teboul 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 2 application with webpack 4 boilerplate 2 | 3 | This repo is a support for [this article](https://medium.com/js-dojo/how-to-configure-webpack-4-with-vuejs-a-complete-guide-209e943c4772) published on Medium 4 | -------------------------------------------------------------------------------- /config/env/dev.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: 'development' 3 | }; 4 | -------------------------------------------------------------------------------- /config/env/prod.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: 'production' 3 | }; 4 | -------------------------------------------------------------------------------- /config/env/staging.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: 'staging' 3 | }; 4 | -------------------------------------------------------------------------------- /config/helpers.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const path = require('path'); 4 | 5 | const _root = path.resolve(__dirname, '..'); 6 | 7 | exports.root = function (args) { 8 | args = Array.prototype.slice.call(arguments, 0); 9 | 10 | return path.join.apply(path, [ _root ].concat(args)); 11 | }; 12 | 13 | exports.assetsPath = function (_path) { 14 | return path.posix.join('static', _path); 15 | }; 16 | -------------------------------------------------------------------------------- /config/webpack.config.common.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const VueLoaderPlugin = require('vue-loader/lib/plugin'); 4 | const HtmlPlugin = require('html-webpack-plugin'); 5 | const MiniCSSExtractPlugin = require('mini-css-extract-plugin'); 6 | const helpers = require('./helpers'); 7 | const isDev = process.env.NODE_ENV === 'development'; 8 | 9 | const webpackConfig = { 10 | entry: { 11 | polyfill: '@babel/polyfill', 12 | main: helpers.root('src', 'main'), 13 | }, 14 | resolve: { 15 | extensions: [ '.js', '.vue' ], 16 | alias: { 17 | 'vue$': isDev ? 'vue/dist/vue.runtime.js' : 'vue/dist/vue.runtime.min.js', 18 | '@': helpers.root('src') 19 | } 20 | }, 21 | module: { 22 | rules: [ 23 | { 24 | test: /\.vue$/, 25 | loader: 'vue-loader', 26 | include: [ helpers.root('src') ] 27 | }, 28 | { 29 | test: /\.js$/, 30 | loader: 'babel-loader', 31 | include: [ helpers.root('src') ] 32 | }, 33 | { 34 | test: /\.css$/, 35 | use: [ 36 | isDev ? 'vue-style-loader' : MiniCSSExtractPlugin.loader, 37 | { loader: 'css-loader', options: { sourceMap: isDev } }, 38 | ] 39 | }, 40 | { 41 | test: /\.scss$/, 42 | use: [ 43 | isDev ? 'vue-style-loader' : MiniCSSExtractPlugin.loader, 44 | { loader: 'css-loader', options: { sourceMap: isDev } }, 45 | { loader: 'sass-loader', options: { sourceMap: isDev } } 46 | ] 47 | }, 48 | { 49 | test: /\.sass$/, 50 | use: [ 51 | isDev ? 'vue-style-loader' : MiniCSSExtractPlugin.loader, 52 | { loader: 'css-loader', options: { sourceMap: isDev } }, 53 | { loader: 'sass-loader', options: { sourceMap: isDev } } 54 | ] 55 | } 56 | ] 57 | }, 58 | plugins: [ 59 | new VueLoaderPlugin(), 60 | new HtmlPlugin({ template: 'index.html', chunksSortMode: 'dependency' }) 61 | ] 62 | }; 63 | 64 | module.exports = webpackConfig; 65 | -------------------------------------------------------------------------------- /config/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const webpack = require('webpack'); 4 | const merge = require('webpack-merge'); 5 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin'); 6 | const helpers = require('./helpers'); 7 | const commonConfig = require('./webpack.config.common'); 8 | const environment = require('./env/dev.env'); 9 | 10 | const webpackConfig = merge(commonConfig, { 11 | mode: 'development', 12 | devtool: 'cheap-module-eval-source-map', 13 | output: { 14 | path: helpers.root('dist'), 15 | publicPath: '/', 16 | filename: 'js/[name].bundle.js', 17 | chunkFilename: 'js/[id].chunk.js' 18 | }, 19 | optimization: { 20 | runtimeChunk: 'single', 21 | splitChunks: { 22 | chunks: 'all' 23 | } 24 | }, 25 | plugins: [ 26 | new webpack.EnvironmentPlugin(environment), 27 | new webpack.HotModuleReplacementPlugin(), 28 | new FriendlyErrorsPlugin() 29 | ], 30 | devServer: { 31 | compress: true, 32 | historyApiFallback: true, 33 | hot: true, 34 | open: true, 35 | overlay: true, 36 | port: 8000, 37 | stats: { 38 | normal: true 39 | } 40 | } 41 | }); 42 | 43 | module.exports = webpackConfig; 44 | -------------------------------------------------------------------------------- /config/webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const webpack = require('webpack'); 4 | const merge = require('webpack-merge'); 5 | const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); 6 | const MiniCSSExtractPlugin = require('mini-css-extract-plugin'); 7 | const UglifyJSPlugin = require('uglifyjs-webpack-plugin'); 8 | const CompressionPlugin = require('compression-webpack-plugin'); 9 | const helpers = require('./helpers'); 10 | const commonConfig = require('./webpack.config.common'); 11 | const isProd = process.env.NODE_ENV === 'production'; 12 | const environment = isProd ? require('./env/prod.env') : require('./env/staging.env'); 13 | 14 | const webpackConfig = merge(commonConfig, { 15 | mode: 'production', 16 | output: { 17 | path: helpers.root('dist'), 18 | publicPath: '/', 19 | filename: 'js/[hash].js', 20 | chunkFilename: 'js/[id].[hash].chunk.js' 21 | }, 22 | optimization: { 23 | runtimeChunk: 'single', 24 | minimizer: [ 25 | new OptimizeCSSAssetsPlugin({ 26 | cssProcessorPluginOptions: { 27 | preset: [ 'default', { discardComments: { removeAll: true } } ], 28 | } 29 | }), 30 | new UglifyJSPlugin({ 31 | cache: true, 32 | parallel: true, 33 | sourceMap: !isProd 34 | }) 35 | ], 36 | splitChunks: { 37 | chunks: 'all', 38 | maxInitialRequests: Infinity, 39 | minSize: 0, 40 | cacheGroups: { 41 | vendor: { 42 | test: /[\\/]node_modules[\\/]/, 43 | name (module) { 44 | const packageName = module.context.match(/[\\/]node_modules[\\/](.*?)([\\/]|$)/)[1]; 45 | return `npm.${packageName.replace('@', '')}`; 46 | } 47 | }, 48 | styles: { 49 | test: /\.css$/, 50 | name: 'styles', 51 | chunks: 'all', 52 | enforce: true 53 | } 54 | } 55 | } 56 | }, 57 | plugins: [ 58 | new webpack.EnvironmentPlugin(environment), 59 | new MiniCSSExtractPlugin({ 60 | filename: 'css/[name].[hash].css', 61 | chunkFilename: 'css/[id].[hash].css' 62 | }), 63 | new CompressionPlugin({ 64 | filename: '[path].gz[query]', 65 | algorithm: 'gzip', 66 | test: new RegExp('\\.(js|css)$'), 67 | threshold: 10240, 68 | minRatio: 0.8 69 | }), 70 | new webpack.HashedModuleIdsPlugin() 71 | ] 72 | }); 73 | 74 | if (!isProd) { 75 | webpackConfig.devtool = 'source-map'; 76 | 77 | if (process.env.npm_config_report) { 78 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 79 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()); 80 | } 81 | } 82 | 83 | module.exports = webpackConfig; 84 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Vue 2 Webpack 4 Boilerplate 7 | 8 | 9 |
10 | 11 | 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-2-webpack-4-boilerplate", 3 | "version": "1.0.0", 4 | "description": "Vue 2 application with webpack 4 boilerplate", 5 | "scripts": { 6 | "dev": "cross-env NODE_ENV=development webpack-dev-server --progress", 7 | "staging": "cross-env NODE_ENV=staging webpack", 8 | "build": "cross-env NODE_ENV=production webpack" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/samteb/vue-2-webpack-4-boilerplate" 13 | }, 14 | "keywords": [ 15 | "Vue", 16 | "Webpack 4" 17 | ], 18 | "author": "samteb ", 19 | "license": "MIT", 20 | "homepage": "https://github.com/samteb/vue-2-webpack-4-boilerplate", 21 | "dependencies": { 22 | "@babel/polyfill": "~7.2", 23 | "vue": "~2.6", 24 | "vue-router": "~3.0" 25 | }, 26 | "devDependencies": { 27 | "@babel/core": "~7.2", 28 | "@babel/plugin-proposal-class-properties": "~7.3", 29 | "@babel/plugin-proposal-decorators": "~7.3", 30 | "@babel/plugin-proposal-json-strings": "~7.2", 31 | "@babel/plugin-syntax-dynamic-import": "~7.2", 32 | "@babel/plugin-syntax-import-meta": "~7.2", 33 | "@babel/preset-env": "~7.3", 34 | "babel-eslint": "~10.0", 35 | "babel-loader": "~8.0", 36 | "compression-webpack-plugin": "~2.0", 37 | "cross-env": "~5.2", 38 | "css-loader": "~2.1", 39 | "eslint": "~5.16", 40 | "eslint-config-standard": "~10.2", 41 | "eslint-friendly-formatter": "~3.0", 42 | "eslint-loader": "~2.1", 43 | "eslint-plugin-html": "~3.0", 44 | "eslint-plugin-import": "~2.14", 45 | "eslint-plugin-node": "~4.2", 46 | "eslint-plugin-promise": "~3.5", 47 | "eslint-plugin-standard": "~3.0", 48 | "eslint-plugin-vue": "~5.1", 49 | "friendly-errors-webpack-plugin": "~1.7", 50 | "html-webpack-plugin": "~3.2", 51 | "mini-css-extract-plugin": "~0.5", 52 | "node-sass": "~4.12", 53 | "optimize-css-assets-webpack-plugin": "~5.0", 54 | "sass-loader": "~7.1", 55 | "uglifyjs-webpack-plugin": "~1.2", 56 | "vue-loader": "~15.6", 57 | "vue-style-loader": "~4.1", 58 | "vue-template-compiler": "~2.6", 59 | "webpack": "~4.29", 60 | "webpack-bundle-analyzer": "~3.3", 61 | "webpack-cli": "~3.2", 62 | "webpack-dev-server": "~3.1", 63 | "webpack-hot-middleware": "~2.24", 64 | "webpack-merge": "~4.2" 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /src/components/AppHome.vue: -------------------------------------------------------------------------------- 1 | 4 | 5 | 10 | 11 | -------------------------------------------------------------------------------- /src/components/AppMedium.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 12 | 13 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | // Import Vue 2 | import Vue from 'vue'; 3 | import VueRouter from 'vue-router'; 4 | 5 | // Import Vue App, routes, store 6 | import App from './App'; 7 | import routes from './routes'; 8 | 9 | Vue.use(VueRouter); 10 | 11 | // Configure router 12 | const router = new VueRouter({ 13 | routes, 14 | linkActiveClass: 'active', 15 | mode: 'history' 16 | }); 17 | 18 | new Vue({ 19 | el: '#app', 20 | render: h => h(App), 21 | router 22 | }); 23 | -------------------------------------------------------------------------------- /src/routes.js: -------------------------------------------------------------------------------- 1 | import AppHome from '@/components/AppHome'; 2 | const AppMedium = () => import('@/components/AppMedium'); 3 | 4 | 5 | const routes = [ 6 | { 7 | path: '/', 8 | name: 'Home', 9 | component: AppHome 10 | }, 11 | { 12 | path: '/medium', 13 | name: 'Medium', 14 | component: AppMedium 15 | } 16 | ]; 17 | 18 | export default routes; 19 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | const environment = (process.env.NODE_ENV || 'development').trim(); 4 | 5 | if (environment === 'development') { 6 | module.exports = require('./config/webpack.config.dev'); 7 | } else { 8 | module.exports = require('./config/webpack.config.prod'); 9 | } 10 | --------------------------------------------------------------------------------