preface

Most people in the development of VUE and other SPA projects will directly use VUE-CLI scaffold development, one is convenient to save a lot of configuration effort, two is vuE-CLI is after all tested and more mature things, problems can also find the corresponding solution on the Internet.

However, if we want to better understand the scaffolding configuration and build packaging mechanism, we need to start from scratch and configure a project like VUe-CLI ourselves. Here, I have made the following simple configuration for you to comment on. I sincerely hope to get your advice on how to solve the problem that Tree Shaking results in missing CSS packaging.

This document mainly includes the following configurations:

  • Distinguish environment variables and merge configurations
  • webpack-dev-serverLocal server
  • HtmlWebpackPluginGenerate HTML
  • CleanWebpackPluginClear folders
  • loaderbabelconfiguration
  • HotModuleReplacementPluginHot update
  • postcss-loaderAdding CSS prefixes
  • vue SPAIntroduction and analysis
  • vue-routerInstallation and use
  • mini-css-extract-pluginThe separation of CSS
  • purifycss-webpack purify-cssEliminate redundant CSS
  • optimize-css-assets-webpack-pluginCompress CSS
  • terser-webpack-pluginCompression js
  • splitChunksExtract common code
  • image-webpack-loaderImage compression
  • gZipTo accelerate the optimization

Project source: github.com/Michael-lzg…

Build a VuE-CLI4 + WebPack Mobile framework from scratch (out of the box)

Without further ado, the old driver will take you on your way immediately.

Build webpack project framework

Structuring the project

  1. Create webpack-vue-CLI folder and npm-init-y to initialize the project

  2. Install webPack-related dependencies

npm i webpack webpack-cli webpack-dev-server webpack-merge --save-dev
Copy the code

If webpack and webpack-CLI are not installed globally, do so first

  1. Create project folders
├ ─ ─ the SRC// Webpack configuration file| - main. Js// Import file├ ─ ─static   // Project package path├ ─ ─ index. HTML/ / HTML templates├ ─ ─ webpack. Base. Js// Package the basic configuration├ ─ ─ webpack. Dev. Js// Local environment configuration├ ─ ─ webpack. Prod. Js// Production environment configuration
Copy the code

The index.html and main.js code is not much to say, and we go straight to webpack configuration.

To distinguish the environment

To optimize packaging, we split webPack configuration into development and production environments.

  • Webpack.base.js public configuration file
  • Webpack.dev.js configuration file for the development environment
  • Webpack.prod. js Configuration file for the production environment

In webpack.dev.js and webpack.prod.js, we can use webpack-merge for configuration merging.

We then define packaging commands for different environments in package.json

"scripts": {
  "dev": "webpack-dev-server --config webpack.dev.js --mode development"."build": "webpack --config webpack.prod.js"
}
Copy the code

Common configuration

Let’s take a look at the common configuration of webpack.base.js and define the entry and exit files

module.exports = {
  entry: {
    index: path.join(__dirname, '/src/main.js'),},output: {
    path: path.join(__dirname, '/dist'), // The place where the packed files are stored
    filename: 'js/[name].[hash].js'.// The hash changes every time you save it}},Copy the code

webpack-dev-server

Webpack provides an optional local development server that is built on Node.js and configured in webpack.dev.js

const merge = require('webpack-merge') // Introduce the webpack-merge function module
const common = require('./webpack.base.js') / / introduce webpack.com mon. Js

module.exports = merge(common, {
  // Merge webpack.common.js into the current file
  devServer: {
    contentBase: './dist'.// Directory of the files loaded by the local server
    port: '8899'.// Set port number to 8088
    inline: true.// Refresh files in real time after modification
    historyApiFallback: true./ / don't jump
    hot: true./ / hot update
  },
  mode: 'development'./ / set mode
})
Copy the code

HtmlWebpackPlugin

HtmlWebpackPlugin simplifies the creation of HTML files. It can automatically produce packaged HTML files for you based on HTML templates. This is for bundles whose file names contain hashes that change each time they are compiled.

plugins: [
  new HtmlWebpackPlugin({
    template: path.join(__dirname, '/index.html'), // New an instance of the plugin and pass in the relevant parameters}),]Copy the code

Now that you have a beggar version of webPack, you can write code and run commands in your development and production environments to see what happens.

Loader configuration

Loader enables Webpack to handle non-javascript files (Webpack itself only understands javaScript). Loader can convert all types of files into valid modules that WebPack can handle, and then you can take advantage of WebPack’s packaging capabilities to process them.

Loader is a loader that handles styles, js, and files.

module: {
  rules: [{test: /\.css$/.// Matches files that end in.css
      use: ['style-loader'.'css-loader'],}, {test: /\.less$/,
      use: ['style-loader'.'css-loader'.'less-loader'],}, {test: /\.js$/,
      loader: 'babel-loader'.include: [resolve('src')]}, {test: /\.(png|jpe? g|gif|svg)(\? . *)? $/,
      loader: 'url-loader'.options: {
        limit: 10000.name: utils.assetsPath('img/[name].[hash:7].[ext]'),},},]}Copy the code

For easy configuration and optimization of babel-loader, we can extract it and create a new.babelrc file in the root directory

{
  "presets": ["env"]
}
Copy the code

CleanWebpackPlugin

The CleanWebpackPlugin is used to clean up the /dist folder before each build and produce the latest package file.

plugins: [
  new HtmlWebpackPlugin({
    template: path.join(__dirname, '/index.html'), // New an instance of the plugin and pass in the relevant parameters
  }),
  new CleanWebpackPlugin(), // The name of the folder to be cleaned
]
Copy the code

HotModuleReplacementPlugin

HotModuleReplacementPlugin (HMR) is a very useful plug-ins, can automatically refresh preview effect, after we modify the code used in the development environment.

  1. Set hot: true in the devServer configuration item

  2. HotModuleReplacementPlugin webpack module’s own, so after introducing webpack, can be directly used in the plugins configuration items.

plugins: [
  new webpack.HotModuleReplacementPlugin(), // Hot update plugin
]
Copy the code

Adding CSS prefixes

When writing CSS, some attributes need to be prefixed manually, such as -webkit-border-radius: 10px; In webpack we can make it add automatically

  1. Install dependencies
npm i postcss-loader autoprefixer -D
Copy the code
  1. Create a new one in the project root directorypostcss.config.jsfile
module.exports = {
  plugins: [
    require('autoprefixer'), // References the Autoprefixer module],}Copy the code
  1. Modify style loader
rules: [
  {
    test: /\.css$/.// Matches files that end in.css
    use: ['style-loader'.'css-loader'.'postcss-loader'],}, {test: /\.less$/,
    use: ['style-loader'.'css-loader'.'postcss-loader'.'less-loader'],},]Copy the code

At this point, a Webpack project is basically set up. Here are vue references and project optimization.

Set up vue SPA template

vue SPA

To build a vue-CLI scaffolding, start by writing code in main.js

import Vue from 'vue'
import App from './App.vue'
new Vue({
  el: '#app'.render: (h) = > h(App),
})
Copy the code

2. Create app.vue in the SRC folder

<div id="app">The SPA project</div>
Copy the code

3. Install dependencies

At this point, we NPM run dev tried to report an error. Since we don’t have dependencies installed, let’s go ahead and install them

npm install vue vue-loader vue-template-compiler -D
Copy the code
  • Vue: Vue source code
  • Vue-loader: parses. Vue files
  • Vue-template-compiler: compiles vUE

4. Configure vue-loader in Webpack

const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
  module: {
    rules: [{test: /\.vue$/,
        loader: 'vue-loader',}]},plugins: [new VueLoaderPlugin()],
}
Copy the code

vue-router

1. Install dependencies

npm install vue-router -D
Copy the code

2. Create router/index in the SRC folder

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

const router = new Router({
  routes: [{path: '/'.component: () = > import('.. /views/Home.vue'),}, {path: '/admin'.component: () = > import('.. /views/admin.vue'),},],})export default router
Copy the code

3. Reference in main.js

import Vue from 'vue'
import App from './App.vue'
import router from './router'

new Vue({
  el: '#app',
  router,
  render: (h) = > h(App),
})
Copy the code

With that, a vue-cli-like scaffolding is set up and you can happily write.vue files for SPA development.

Webpack optimizes packaging

The separation of CSS

Although the idea of Webpack is to pack CSS and JS into a single file, if we want to separate CSS, we use the mini-CSS-extract-plugin. Compared to the extract-text-webpack-plugin, it has the following advantages:

  • Asynchronous loading
  • Better performance without recompiling
  • Easier to use
  • Only for CSS

But the Mini-CSS-extract-Plugin doesn’t support HMR, so we can only use it in production.

1. Install dependencies

npm install mini-css-extract-plugin -D
Copy the code

2. Configure loader and plugin in webpack.prod.js

module: {
  rules: [{test: /\.(le|c)ss$/,
      use: [
        {
          loader: MiniCssExtractPlugin.loader,
          options: {
            publicPath: '.. / '}},'css-loader'.'postcss-loader'.'less-loader',]}]},plugins: [
  new MiniCssExtractPlugin({
    filename: "css/[name].[contenthash:8].css".chunkFilename: 'css/[id].[contenthash:8].css'})]Copy the code

To separate the CSS, replace style-loader in the CSS Loader with MiniCssExtractPlugin

Eliminate redundant CSS

Sometimes we write too much CSS or duplicate it, which creates extra code that we want to remove in production.

1. Install dependencies

npm i purifycss-webpack purify-css glob -D
Copy the code

2. Webpack.prod. js configuration

const path = require('path')
const PurifyCssWebpack = require('purifycss-webpack') // Introduce the PurifyCssWebpack plugin
const glob = require('glob') // Introduces the glob module, which is used to scan all CSS references in HTML files

module.exports = merge(common, {
  plugins: [
    new PurifyCssWebpack({
      paths: glob.sync(path.join(__dirname, 'src/*.html')),})],})Copy the code

Compress CSS

We want to reduce the size of the CSS package by using the optimization-CSS-assets-webpack-plugin. 1. Install dependencies

npm install optimize-css-assets-webpack-plugin -D
Copy the code

2. Webpack.prod. js configuration

const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin") // Compress the CSS code

optimization: {
  minimizer: [
    / / compress CSS
    new OptimizeCSSAssetsPlugin({})
  ]
Copy the code

Compression js

Webpackage 4.0 uses terser-webpack-plugin by default and uglifyjs-webpack-plugin by default. The difference between the two is that the latter does not compress ES6 very well. At the same time, we can turn on the PARALLEL parameter to use multi-process compression to speed up compression.

1. Install dependencies

npm install terser-webpack-plugin -D
Copy the code

2. Webpack.prod. js configuration

const TerserPlugin = require('terser-webpack-plugin') // Compress the js code

optimization: {
  minimizer: [
    new TerserPlugin({
      parallel: 4.// Start several processes to handle compression, os.cpus().length-1 by default
      cache: true.// Whether to cache
      sourceMap: false,})./ / compress CSS
    new OptimizeCSSAssetsPlugin({}),
  ]
}
Copy the code

Extract common code

When packaging with WebPack, we wanted to be able to separate our own code from third-party libraries that don’t update very often, like things in the Vue family bucket. Webpack4 is configured using splitChunks.

optimization: {
  / / separate chunks
  splitChunks: {
    chunks: 'all'.cacheGroups: {
      vendor: {
        name: "vendor".test: /[\\/]node_modules[\\/]/,
        priority: 10.chunks: "initial" // Package only the third party that you originally relied on}}}},Copy the code

Image compression

Some images in the project are too big to load, so we use image-webpack-loader to compress them.

1. Install dependencies

npm install image-webpack-loader -D
Copy the code

2. Configure the Loader

{
  test: /\.(png|jpg|svg|gif)$/,
  use: [
    {
      loader: 'url-loader'.options: {
        esModule: false.limit: 1000.// Only images smaller than 1KB can be converted to base64
        outputPath: 'images'.// Set the name of the folder to store the image after packaging
        name: '[name][hash:8].[ext]'}}, {loader: 'image-webpack-loader'.options: {
        // Compress the JPEG configuration
        mozjpeg: {
          progressive: true.quality: 65
        },
        // Use imagemin**-optipng to compress PNG, enable: false to disable PNG
        optipng: {
          enabled: false,},// // compress PNG using Imagemin-pngquant
        pngquant: {
          quality: [0.65.0.90].speed: 4
        },
        // Compress the GIF configuration
        gifsicle: {
          interlaced: false,},// Enable webp to compress JPG and PNG images into WebP format
        webp: {
          quality: 75}}}]}Copy the code

GZip accelerates optimization

All modern browsers support gzip compression. Enabling gzip compression greatly reduces the size of transmitted resources, shortens the download time of resources, reduces the first blank screen time, and improves user experience.

Gzip has the best compression effect on files based on text format (such as CSS, JavaScript and HTML), and can achieve up to 70-90% compression rate when compressing large files. Gzip has poor compression effect on already compressed resources (such as images).

const CompressionPlugin = require('compression-webpack-plugin')
configureWebpack: (config) = > {
  if (process.env.NODE_ENV === 'production') {
    config.plugins.push(
      new CompressionPlugin({
        // Gzip compression configuration
        test: /\.js$|\.html$|\.css/.// Match the file name
        threshold: 10240.// Compress data that exceeds 10KB
        deleteOriginalAssets: false.// Whether to delete the original file}}}))Copy the code

Tree-shaking (Help, Production environment packaging can’t make a style)

Building projects this way has always worked well in the development environment, but as soon as you run the NPM run build and open the page, all the styles are missing. Open the dist/ CSS folder and find three CSS files, only index. CSS has some files (main.js introduced initial styles, but also incomplete), and the other two CSS files are empty, that is, the styles in the. Vue are all missing.

Webpack4 uses tree-shaking by default. The code packaged at the module level only contains the modules that are referenced and executed, and the modules that are not referenced or executed are removed to reduce packets. But I have configured sideEffects in package.json according to relevant resources, but it is still useless, I am really upset!!

"sideEffects": [
    "*.less"."*.css"."*.vue"
  ]
Copy the code

Here for help, if you have encountered similar problems or know how to solve them, please give advice, little brother would be grateful!!

Recommend the article

Build a VuE-CLI4 + WebPack mobile framework (out of the box)
Encapsulate a TOAST and Dialog component and publish it to NPM
Build a WebPack project from scratch
Summary of several webpack optimization methods
Summary of advanced application of VUE knowledge system
Summarize the practical skills of vUE knowledge system
Summarize the basic introduction to vUE knowledge system
Summary of mobile H5 development tips.