The opening

The original address: www.ccode.live/lentoo/list…

Project code: github.com/lentoo/vue-…

Some time ago, I saw some friends in the group were asked this kind of question by the interviewer during the interview. We usually develop vUE project, I believe that most people are using VUE-CLI scaffolding generated project architecture, and then NPM run install install dependencies, NPM run serve started the project and then began to write business code.

However, if you don’t have a clear understanding of webpack packaging and configuration in the project, you may not know how to solve problems, or you may not be able to extend new functions through Webpack.

This article is mainly to tell partners, how step by step through Webpack4 to build their own VUE development environment

First, we need to know the vue-CLI generated project, which functions have been configured for us?

  1. ES6Code conversion toES5code
  2. scss/sass/less/stylusturncss
  3. .vueFile conversion tojsfile
  4. usejpg,png.fontEtc resource files
  5. Automatically adds prefixes for CSS browser manufacturers
  6. Code hot update
  7. Resource preloading
  8. Each build cleans up the previously generated code
  9. Defining environment variables
  10. Distinguish between development environment packaging and production environment packaging
  11. .

1. The structures,webpackBasic environment

This article does not go into the details of what Webpack is, but if you are not sure, you can check out the WebPack website first

To put it simply, Webpack is a module packer that can analyze your project dependent modules and some browsers can not directly run the language JSX, VUE, etc., into JS, CSS files, etc., for the browser to use.

1.1 Initializing the Project

Execute NPM init on the command line and press Enter to generate some basic project information. Finally, a package.json file is generated

npm init
Copy the code

1.2 installationwebpack

Write a little code to test itwebpackCheck whether the installation is successful

Create a new SRC folder and create a main.js file

// src/main.js
console.log('hello webpack')
Copy the code

Then add a script command under package.json

Then run the command

npm run serve
Copy the code

If a main.js file is generated in the dist directory, then webPack is working properly

2. Start to configure functions

  • Create a newbuildFolder, for storagewebpackConfigure related files
  • inbuildCreate a new folder under this folderwebpack.config.js, the configurationwebpackBasic configuration of
  • Modify thewebpack.config.jsconfiguration

  • Modify thepackage.jsonFile will be added previouslyserveModified to
"serve": "webpack ./src/main.js --config ./build/webpack.config.js"
Copy the code

2.1 configurationES6/7/8ES5code

  • Installation-dependent dependencies
npm install babel-loader @babel/core @babel/preset-env
Copy the code
  • Modify thewebpack.config.jsconfiguration

  • Add one in the project root directorybabel.config.jsfile

  • Then performnpm run serveCommand, you can see that the ES6 code has been converted to ES5 code

2.1.1 ES6/7/8 Apies5

Babel-loader will only convert ES6/7/8 syntax to ES5 syntax, but not for new apis.

Babel-polyfill provides an implementation of the new syntax for clients that do not support it

  • The installation
npm install @babel/polyfill
Copy the code
  • Modify thewebpack.config.jsconfiguration

Add @babel-Polyfill to entry

2.1.2 Import on demandpolyfill

2.1.2 and 2.1.1 only need to be configured

Revised time 2019-05-05, from the comment area XI all over the sky remind

  • Installation-dependent dependencies
npm install core-js@2 @babel/runtime-corejs2 -S
Copy the code
  • Modify the Babel – config. Js

When you configure to import polyfills on demand, Babel automatically imports the relevant polyfills for functions above ES6, which greatly reduces the volume of packaging and compilation

2.2 configurationscsscss

When no CSS-related loader is configured, an error message is displayed if SCSS and CSS-related files are imported

  • Installation-dependent dependencies
npm install sass-loader dart-sass css-loader style-loader -D
Copy the code

Sas-loader, DARt-sass mainly converts SCSS/SASS syntax to CSS

Css-loader mainly parses CSS files

Style-loader mainly parses CSS to the style of HTML pages

  • Modify thewebpack.config.jsconfiguration

2.3 Configuring the PostCSS To Automatically add the CSS3 prefix

  • Installation-dependent dependencies
npm install postcss-loader autoprefixer -D
Copy the code
  • Modify thewebpack.config.jsconfiguration

  • Create a new one under the project rootpostcss.config.js

2.3 the use ofhtml-webpack-pluginTo create an HTML page

Use htML-webpack-plugin to create HTML pages and automatically introduce packaged js files

  • Install dependencies
npm install html-webpack-plugin -D
Copy the code
  • Create a new public/index.html page

      
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="Width = device - width, initial - scale = 1.0">
  <meta http-equiv="X-UA-Compatible" content="ie=edge">
  <title>Document</title>
</head>
<body>
  <div id="app"></div>
</body>
</html>
Copy the code
  • Modify thewebpack-config.jsconfiguration

2.4 Configuring the devServer Hot Update Function

Through the hot update function of the code, we can achieve without refreshing the page, update our page

  • Install dependencies
npm install webpack-dev-server -D
Copy the code
  • Modify thewebpack.config.jsconfiguration

By configuring devServer and HotModuleReplacementPlugin plug-in to realize hot update

2.5 Configuring webPack to pack image, media, and font files

  • Install dependencies
npm install file-loader url-loader -D
Copy the code

File-loader parses the FILE URL and copies the file to the output directory

The url-loader function is similar to file-loader, if the file size is smaller than the limit. Base64 encoding is returned, otherwise use file-loader to copy the file to the output directory

  • Modify thewebpack-config.jsConfiguration to addrulesConfiguration, respectively for the picture, media, font file configuration
// build/webpack.config.js
const path = require('path')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const webpack = require('webpack')
module.exports = {
  // Omit other configurations...
  module: {
    rules: [
      // ...
      {
        test: /\.(jpe? g|png|gif)$/i.use: [{loader: 'url-loader'.options: {
              limit: 4096.fallback: {
                loader: 'file-loader'.options: {
                    name: 'img/[name].[hash:8].[ext]'}}}}]}, {test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\? . *)? $/.use: [{loader: 'url-loader'.options: {
              limit: 4096.fallback: {
                loader: 'file-loader'.options: {
                  name: 'media/[name].[hash:8].[ext]'}}}}]}, {test: /\.(woff2? |eot|ttf|otf)(\? . *)? $/i.use: [{loader: 'url-loader'.options: {
              limit: 4096.fallback: {
                loader: 'file-loader'.options: {
                  name: 'fonts/[name].[hash:8].[ext]'}}}}]},]},plugins: [
    // ...]}Copy the code

3. Letwebpackidentify.vuefile

  • Dependency files required for installation
npm install vue-loader vue-template-compiler cache-loader thread-loader -D
npm install vue -S
Copy the code

Vue-loader parses. Vue files

Vue-template-compiler is used to compile templates

Cache-loader Is used to cache the result of loader compilation

Thread-loader runs the Loader using a pool of workers, each of which is a Node.js process.

  • Modify thewebpack.config.jsconfiguration
// build/webpack.config.js
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
  // Specify the packaging mode
  mode: 'development'.entry: {
    // ...
  },
  output: {
    // ...
  },
  devServer: {
    // ...
  },
  resolve: {
    alias: {
      vue$: 'vue/dist/vue.runtime.esm.js'}},module: {
    rules: [{test: /\.vue$/.use: [{loader: 'cache-loader'
          },
          {
            loader: 'thread-loader'
          },
          {
            loader: 'vue-loader'.options: {
              compilerOptions: {
                preserveWhitespace: false},}}]}, {test: /\.jsx? $/.use: [{loader: 'cache-loader'
          },
          {
            loader: 'thread-loader'
          },
          {
            loader: 'babel-loader'}},// ...]},plugins: [
    // ...
    new VueLoaderPlugin()
  ]
}
Copy the code
  • Test the
  1. Create a new app.vue in SRC
// src/App.vue
<template>
  <div class="App">
    Hello World
  </div>
</template>

<script>
export default {
  name: 'App'.data() {
    return{}; }}; </script> <style lang="scss" scoped>
.App {
  color: skyblue;
}
</style>
Copy the code
  1. Modify themain.js
import Vue from 'vue'
import App from './App.vue'

new Vue({
  render: h => h(App)
}).$mount('#app')
Copy the code
  1. Run the

npm run serve

4. Define environment variables

The DefinePlugin plugin provided by WebPack makes it easy to define environment variables

plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        VUE_APP_BASE_URL: JSON.stringify('http://localhost:3000')}}),]Copy the code

5. Distinguish between production and development environments

Create two new files

  • Used in the webpack.dev.js development environment

  • Webpack.prod. js is used in production environments

  • Webpack.config.js common configuration

  • Differences between development and production environments

5.1 Development Environment

  1. No need to compress the code
  2. Hot update required
  3. CSS does not need to be extracted into a CSS file
  4. sourceMap
  5. .

5.2 Production Environment

  1. The compression code
  2. Hot updates are not required
  3. Extract CSS and compress CSS files
  4. sourceMap
  5. Clear the contents of the last build before building
  6. .
  • Installation required dependencies
npm i @intervolga/optimize-cssnano-plugin mini-css-extract-plugin clean-webpack-plugin webpack-merge copy-webpack-plugin  -DCopy the code
  1. @intervolga/optimize-cssnano-pluginUsed to compress CSS code
  2. mini-css-extract-pluginUse to extract CSS to a file
  3. clean-webpack-pluginUsed to delete the file from the last build
  4. webpack-mergemergewebpackconfiguration
  5. copy-webpack-pluginUsers copy static resources

5.3 Configuring the Development Environment

  • build/webpack.dev.js
// build/webpack.dev.js
const merge = require('webpack-merge')
const webpackConfig = require('./webpack.config')
const webpack = require('webpack')
module.exports = merge(webpackConfig, {
  mode: 'development'.devtool: 'cheap-module-eval-source-map'.module: {
    rules: [{test: /\.(scss|sass)$/.use: [{loader: 'style-loader'
          },
          {
            loader: 'css-loader'.options: {
              importLoaders: 2}}, {loader: 'sass-loader'.options: {
              implementation: require('dart-sass')}}, {loader: 'postcss-loader'}]},]},plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: JSON.stringify('development')}}),]})Copy the code
  • webpack.config.js
// build/webpack.config.js
const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
  entry: {
    // Configure the entry file
    main: path.resolve(__dirname, '.. /src/main.js')},output: {
    // Configure the directory for the output of the packaged files
    path: path.resolve(__dirname, '.. /dist'),
    // The name of the generated JS file
    filename: 'js/[name].[hash:8].js'.// The name of the chunk generated
    chunkFilename: 'js/[name].[hash:8].js'.// Path of resource reference
    publicPath: '/'
  },
  devServer: {
    hot: true.port: 3000.contentBase: './dist'
  },
  resolve: {
    alias: {
      vue$: 'vue/dist/vue.runtime.esm.js'
    },
    extensions: [
      '.js'.'.vue']},module: {
    rules: [{test: /\.vue$/.use: [{loader: 'cache-loader'
          },
          {
            loader: 'vue-loader'.options: {
              compilerOptions: {
                preserveWhitespace: false},}}]}, {test: /\.jsx? $/.loader: 'babel-loader'
      },

      {
        test: /\.(jpe? g|png|gif)$/.use: [{loader: 'url-loader'.options: {
              limit: 4096.fallback: {
                loader: 'file-loader'.options: {
                  name: 'img/[name].[hash:8].[ext]'}}}}]}, {test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\? . *)? $/.use: [{loader: 'url-loader'.options: {
              limit: 4096.fallback: {
                loader: 'file-loader'.options: {
                  name: 'media/[name].[hash:8].[ext]'}}}}]}, {test: /\.(woff2? |eot|ttf|otf)(\? . *)? $/i.use: [{loader: 'url-loader'.options: {
              limit: 4096.fallback: {
                loader: 'file-loader'.options: {
                  name: 'fonts/[name].[hash:8].[ext]'}}}}]},]},plugins: [
    new VueLoaderPlugin(),

    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '.. /public/index.html')}),new webpack.NamedModulesPlugin(),
    new webpack.HotModuleReplacementPlugin(),
  ]
}
Copy the code

5.4 Configuring the Production Environment

const path = require('path')
const merge = require('webpack-merge')
const webpack = require('webpack')
const webpackConfig = require('./webpack.config')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssnanoPlugin = require('@intervolga/optimize-cssnano-plugin');
/* Clean-webpack-plugin 3.0 + requires the use of object structures */
// const CleanWebpackPlugin = require('clean-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const CopyWebpackPlugin = require('copy-webpack-plugin')
module.exports = merge(webpackConfig, {
  mode: 'production'.devtool: '#source-map'.optimization: {
    splitChunks: {
      cacheGroups: {
        vendors: {
          name: 'chunk-vendors'.test: /[\\\/]node_modules[\\\/]/.priority: - 10.chunks: 'initial'
        },
        common: {
          name: 'chunk-common'.minChunks: 2.priority: - 20.chunks: 'initial'.reuseExistingChunk: true}}}},module: {
    rules: [{test: /\.(scss|sass)$/.use: [{loader: MiniCssExtractPlugin.loader
          },
          {
            loader: 'css-loader'.options: {
              importLoaders: 2}}, {loader: 'sass-loader'.options: {
              implementation: require('dart-sass')}}, {loader: 'postcss-loader'}]},]},plugins: [
    new webpack.DefinePlugin({
      'process.env': {
        NODE_ENV: 'production'}}),new MiniCssExtractPlugin({
      filename: 'css/[name].[contenthash:8].css'.chunkFilename: 'css/[name].[contenthash:8].css'
    }),
    new OptimizeCssnanoPlugin({
      sourceMap: true.cssnanoOptions: {
        preset: [
          'default',
          {
            mergeLonghand: false.cssDeclarationSorter: false}}}),new CopyWebpackPlugin([
      {
        from: path.resolve(__dirname, '.. /public'),
        to: path.resolve(__dirname, '.. /dist')}]),new CleanWebpackPlugin()
  ]
})

Copy the code

5.5 modify the package. The json

"scripts": {
    "serve": "webpack-dev-server --config ./build/webpack.dev.js"."build": "webpack --config ./build/webpack.prod.js"
},
Copy the code

6 Packaging Analysis

Sometimes we need to take a look at what’s packed in the WebPack,

This is where the module analysis tool webpack-bundle-Analyzer comes in

  • Install dependencies
npm install --save-dev webpack-bundle-analyzer
Copy the code
  • Modify thewebpack-prod.jsThe configuration,pluginsAdd a plug-in to the property

In the development environment, we do not need to do module packaging analysis, so we configure the plug-in in the production environment configuration items

  • Run the package command
npm run build
Copy the code

The page is automatically displayed after the command is executed successfully

Integration of 7.VueRouter.Vuex

  1. The first is installing dependencies
npm install vue-router vuex --save
Copy the code

7.1 integrationVue-Router

  • Add view component insrcAdd two view components to the directorysrc/views/Home.vuesrc/views/About.vue
// src/views/Home.vue
<template>
  <div class="Home">
    <h2>Home</h2>
  </div>
</template>

<script>
export default {
  name: 'Home',

  data() {
    return{}; }};</script>

<style lang="scss" scoped>
</style>
Copy the code

About. Vue is the same as Home. Vue

  • The route configuration file is added

Add a router/index.js file in the SRC directory

// src/router/index.js
import Vue from 'vue'
import VueRouter from "vue-router";
import Home from '.. /views/Home';
import About from '.. /views/About';
Vue.use(VueRouter)
export default new VueRouter({
  mode: 'hash'.routes: [{path: '/Home'.component: Home
    },
    {
      path: '/About'.component: About
    },
    {
      path: The '*'.redirect: '/Home'}]})Copy the code
  • Modify themain.jsfile
// main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'

new Vue({
  router,
  render: h= > h(App)
}).$mount('#app')
Copy the code
  • Modify theApp.vuecomponent
// app. vue // SRC/app. vue <template> <div class= // app. vue <template> <div class="App"> Hello World </div> <div> // Which router-link component is used to navigate to <router-link to="/Home">go Home</router-link>
      <router-link to="/About">go About</router-link> </div> <div> // to display the matched routing view component </router-view> </div> </template> <script>export default {
  name: 'App'.data() {
    return{}; }}; </script> <style lang="scss" scoped>
.App {
  color: skyblue;
}
</style>
Copy the code

Run the NPM run serve command. If the configuration is correct, click different routes and switch to different routing views

7.2 Configuring Lazy Route Loading

In the case of lazy route loading without configuration, our route components will be packed into the same JS file when packaging. As our view components become more and more, this js file will become bigger and bigger. This can then lead to longer requests for the file, which ultimately affects the user experience

  1. Install dependencies
npm install @babel/plugin-syntax-dynamic-import --save-dev
Copy the code
  1. Modify thebabel.config.js
module.exports = {
  presets: [["@babel/preset-env",
      {
        useBuiltIns: "usage"}]],plugins: [
     // Add this
    '@babel/plugin-syntax-dynamic-import']}Copy the code
  1. Modify therouter/index.jsRouting profile
import Vue from 'vue'
import VueRouter from "vue-router";
Vue.use(VueRouter)
export default new VueRouter({
  mode: 'hash'.routes: [{path: '/Home'.component: (a)= > import(/* webpackChunkName: "Home" */ '.. /views/Home.vue')
      // component: Home
    },
    {
      path: '/About'.component: (a)= > import(/* webpackChunkName: "About" */ '.. /views/About.vue')
      // component: About
    },
    {
      path: The '*'.redirect: '/Home'}]})Copy the code
  1. Run the commandnpm run buildCheck to see if it is generatedHome... jsFiles andAbout... jsfile

7.3 integrated Vuex

  1. insrcCreate a new one in the directorystore/index.jsfile
// store/index.js
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const state = {
  counter: 0
}
const actions = {
  add: ({commit}) = > {
    return commit('add')}}const mutations = {
  add: (state) = > {
    state.counter++
  }
}
const getters = {
  getCounter (state) {
    return state.counter
  }
}
export default new Vuex.Store({
  state,
  actions,
  mutations,
  getters
})
Copy the code
  1. Modify themain.jsFile to importvuex
// main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'
import store from './store'  // ++
new Vue({
  router,
  store,    // ++
  render: h= > h(App)
}).$mount('#app')
Copy the code
  1. Modify theApp.vueTo view the vuEX configuration
// App.vue
<template>
  <div class="App">
    <div>
      <router-link to="/Home">go Home</router-link>
      <router-link to="/About">go About</router-link>
    </div>
    <div>
      <p>{{getCounter}}</p>
      <button @click="add">add</button>
    </div>
    <div>
      <router-view></router-view>
    </div>
  </div>
</template>
<script>
import { mapActions, mapGetters } from 'vuex'
export default {
  name: 'App',
  data() {
    return {};
  },
  computed: {
    ...mapGetters(['getCounter'])},methods: {
    ...mapActions(['add'])}};</script>
<style lang="scss" scoped>
.App {
  text-align: center;
  color: skyblue;
  font-size: 28px;
}
</style>
Copy the code
  1. Run the commandnpm run serve

As you click the button, you can see that our getCounter keeps growing

8 summarizes

So far, we have successfully built a VUE development environment by ourselves, but there are still some features lacking, interested partners can communicate. There are still a lot of holes to tread in the construction process.

If you are not familiar with WebPack, it is recommended to build your own. What does vuE-CLI do for us

Project code: github.com/lentoo/vue-…

Recommended reading

  1. Use webPack’s various plug-ins to increase your development efficiency

  2. Vue-cli3 project from build optimization to Docker deployment

  3. Here’s what Event Loop used to look like

  4. Build an SSR application with VUE-CLI3

Welcome to attention

Welcome to pay attention to the public account “code development”, share the latest technical information every day