Webpack5 + vue3
Tags: beginners, vue, webpack, javascript
Published: 2022-01-05 11:27:25

Nevertheless you can create a simple vue app by

`npm install --save-dev @vue/cli`
`vue create vue3-project`

but it is too simple. Sometimes we need to be close to bare metal - then we need a custom build with our own `webpack.config.js`. Reasons you might need that:

- you are a skilled webpack user
- you have a proven webpack config from a previous project
- you want to integrate with some third parties

Here a simple proven webpack.config.js which allows using `Single File Components (SFC)`. Here is a project structure we are going to use:

![Huge Vue project structure with single file components](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xlikn7ahgdn27621g47f.png)

Features included:
- CSS modules
- extract node_modules to a separate file (or chunk, or bundle)

`webpack.config.js`:

```javascript
const path = require('path');
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin');
const { VueLoaderPlugin } = require("vue-loader");
const { CleanWebpackPlugin } = require("clean-webpack-plugin");



const src  = path.resolve(__dirname, 'src');
const dist = path.resolve(__dirname, 'dist');


module.exports = (env, argv) => {
    const IS_PRODUCTION = argv.mode === 'production';

    const config = {
        entry: './src/index.js',
        output: {
            path: dist,
            filename: "[name]-[contenthash].js",
        },

        resolve: {
            alias: {
                "@": src
            }
        },
        mode: argv.mode,
        devServer: {
            static: dist
        },
        plugins: [
            new HtmlWebpackPlugin(),
            new VueLoaderPlugin(),
            new CleanWebpackPlugin(),
        ],
        module: {
            rules: [{
                test: /\.vue$/,
                loader: "vue-loader",
                exclude: /node_modules/
            }, {
                test: /\.css$/,
                use: [
                    IS_PRODUCTION ? MiniCssExtractPlugin.loader : "style-loader",
                    {
                        loader: "css-loader",
                        options: {
                            modules: {
                                localIdentName: "[local]--[hash:base64:6]",
                            },
                        }
                    }
                ]
            }, {
                test: /\.js$/,
                loader: "babel-loader",
                exclude: /node_modules/
            }, {
                test: /\.(png|jpe?g|gif|webm|mp4|svg)$/,
                loader: "file-loader",
                options: {
                    outputPath: "assets"
                }
            }]
        },
        optimization: {
            minimizer: [
                // extend default plugins
                `...`,
                // HTML and JS are minified by default if config.mode === production.
                // But for CSS we need to add this:
                new CssMinimizerPlugin()
            ],
            splitChunks: {
                cacheGroups: {
                    commons: {
                      test: /[\\/]node_modules[\\/]/,
                      name: 'node_modules',
                      chunks: 'all',
                    },
                },
            },
        }
    };


    if (IS_PRODUCTION) {
        // put all CSS files to a single <link rel="stylesheet" href="...">
        config.plugins.push(new MiniCssExtractPlugin({
            filename: "[contenthash].css"
        }));

    } else {
        // config.devtool = "inline-source-map";
    }

    return config;
}
```

`package.json`:
```json
  "scripts": {
    "start": "webpack serve --open --mode=development",
    "build": "webpack --mode=production --progress",
    "dist-clean": "rm -fr dist/*"
  },
```

Full project https://github.com/vinogradov/webpack-templates/tree/main/webpack5-simple-vue3. Thanks!