webpack4搭建vue开发环境

1.需求目标

大家开发业务时最顺手的是vue-cli,大部分的封装配置都做好了,这篇文章是用webpack4搭建这样的环境,
那vue-cli已经配置好了功能呢?

 1. ES6代码转换成ES5代码 
 2. scss/sass/less/stylus转css 
 3. .vue文件转换成js文件 
 4. 使用 jpg、png,font等资源文件 
 5. 自动添加css各浏览器产商的前缀 
 6. 代码热更新 
 7. 资源预加载
 8.  每次构建代码清除之前生成的代码
 9. 定义环境变量
 10. 区分开发环境打包跟生产环境打包

2.搭建webpack环境

2.1 初始化项目

执行npm init命令,生成基本的配置信息,和一个package.json文件

npm init
2.2 安装webpack
 //安装特定的版本后面可以接@version
 npm install --save-dev webpack@<version>
 npm install --save-dev webpack-cli

3 开始配置功能

 - 在根目录下创建build文件夹,用来存放配置文件 
 - 在build文件夹中创建webpack.config.js,这个文件就是用来配置功能的文件

webpack4搭建vue开发环境

在package.json中配置脚本命令,这样我们就可以用 npm run dev命令 启动项目了.

webpack4搭建vue开发环境

3.1 配置ES 6/7/8 转ES5代码功能
安装相关依赖文件:
npm install babel-loader babel-core babel-preset-env webpack

webpack4搭建vue开发环境

3.2配置scss转css
 安装相关依赖文件,官网安装如下:
 npm install sass-loader node-sass webpack --save-dev
但我这里配置的是dart-sass,把node-sass换成dart-sass即可

webpack4搭建vue开发环境

因为处理的顺序是sass-loader->css-loader->style-loader,顺序不能乱,里面的参数可以根据需要自行添加

sass-loader, dart-sass主要是将 scss/sass 语法转为css

css-loader主要是解析 css 文件

style-loader 主要是将 css 解析到 html页面 的 style 上
3.3 配置postcss实现CSS3添加浏览器前缀
 添加依赖文件
 npm install --save-dev autoprefixer

webpack4搭建vue开发环境

前面的配置不变,只要在,sass-loader后面再添加一个postcss-loader
3.4 配置html-webpack-plugin 创建html启动首页
1.安装依赖文件
npm install --save-dev html-loader
2.新建 ./public/index.html, 注意这里一定要添加一个id为app的div!!!!!!
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app"></div>
    
</body>
</html>
在最外面先引用,再放在plugins里
const HtmlWebpackPlugin = require("html-webpack-plugin");

webpack4搭建vue开发环境

3.5 配置devServer 热更新功能
1.安装devServer依赖文件
npm install webpack-dev-server --save-dev
2.修改webpack.config.js
//module.exports外面
let webpack = require('webpack');
//module.exports里面
devServer: {
    contentBase: "./dist", //要放在服务器上的文件名
    port: 3003, //设置端口
    open: true, //设置浏览器自动打开
    hotOnly: true, //只热更新,不刷新浏览器
  },
   plugins:[
      //热更新模块插件
    new webpack.HotModuleReplacementPlugin()
    ],

3.6 配置file-loader 打包 图片、媒体、字体等文件
安装file-loader依赖文件
npm install --save-dev file-loader
 {
        //url-loader 功能与 file-loader 类似,如果文件小于限制的大小。
        //则会返回 base64 编码,否则使用 file-loader 将文件复制到输出的目录中
        test: /\.(jpe?g|png|gif)$/i,
        use: [
          {
            loader: "url-loader",
            options: {
              limit: 4096,
              fallback: {
                loader: "file-loader",
                options: {
                  esModule: false, 
                  name: "[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]",
                },
              },
            },
          },
        ],
      },

4 配置vue相关功能,识别.vue结尾的文件

npm install vue-loader vue-template-compiler cache-loader thread-loader -D
npm install vue -S

vue-loader 用于解析.vue文件
vue-template-compiler 用于编译模板
cache-loader 用于缓存loader编译的结果
thread-loader 使用 worker 池来运行loader,每个 worker 都是一个 node.js 进程。
const VueLoaderPlugin = require("vue-loader/lib/plugin");

module:{
rules:[
 {
        test: /\.vue$/,
        exclude: /node_modules/,
        use: [
          {
            loader: "cache-loader",
          },
          {
            loader: "thread-loader",
          },
          {
            loader: "vue-loader",
            options: {
              compilerOptions: {
                preserveWhitespace: false,
              },
            },
          },
        ],
      },
]

  plugins:[
     new VueLoaderPlugin()
     ]
1.测试一下,在 src 新建一个 App.vue
// 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>
2.修改main.js
import Vue from 'vue'
import App from './App.vue'

new Vue({
  render: h => h(App)
}).$mount('#app')		//这个#app就是挂载到上面说的/public/index.html上的.

5自定义环境变量

webpack自带的DefinePlugin 允许创建一个在编译时可以配置的全局常量。
plugins:[
new webpack.DefinePlugin({
  'SERVICE_URL': JSON.stringify('http://localhost:3003') 	//这样就不用写一长串字符了
})
]

6 区分生产环境和开发环境

把webpack.config.js分为3份,
webpack4搭建vue开发环境

 - webpack.dev.config.js 开发环境使用
 - webpack.prod.config.js 生产环境使用
 - webpack.config.js 公用配置
6.1 开发环境
 1. 不需要压缩代码 
 2. 需要热更新 
 3. css不需要提取到css文件
6.2 生产环境
 1. 压缩代码 
 2. 不需要热更新 
 3. 提取css,
 4. 压缩css文件  

还需要的额外依赖文件:自己去npm下载

css-minimizer-webpack-plugin 用于压缩css代码
mini-css-extract-plugin 用于提取css到文件中
clean-webpack-plugin 用于删除上次构建的文件
webpack-merge 合并 webpack配置
copy-webpack-plugin 用户拷贝静态资源
6.2 webpack.config.js
const path = require("path");
const VueLoaderPlugin = require("vue-loader/lib/plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const CleanWebpackPlugin = require("clean-webpack-plugin");
const BundleAnalyzerPlugin = require("webpack-bundle-analyzer").BundleAnalyzerPlugin;
const CopyPlugin = require("copy-webpack-plugin");
//公共配置
module.exports = {
  entry: {
    main: [
      path.resolve(__dirname, "../src/main.js"), //入口文件为/src/main.js
    ],
  },
  output: {
    filename: "js/[name].[hash].js", //[name]][hash].js,name可以设置,
    chunkFilename: "js/[name].[hash].js", //异步加载的模块放在这里
    path: path.resolve(__dirname, "../dist"), //设置输出文件夹跟build同一级
    publicPath: "/",
  },
  devServer: {
    contentBase: "./dist", //要放在服务器上的文件名
    port: 3003, //设置端口
    open: true, //设置浏览器自动打开
    hotOnly: true, //只热更新,不刷新浏览器
  },
  module: {
    rules: [
      {
        //处理html
        test: /\.(html)$/,
        use: {
          loader: "html-loader",
          options: {
            //默认attrs=img:src,处理img的src属性,
            attributes: true,
          },
        }
      },
      {
        test: /\.vue$/,
        exclude: /node_modules/,
        use: [
          {
            loader: "cache-loader",
          },
          {
            loader: "thread-loader",
          },
          {
            loader: "vue-loader",
            options: {
              compilerOptions: {
                preserveWhitespace: false,
              },
            },
          },
        ],
      },
     
      {
        //url-loader 功能与 file-loader 类似,如果文件小于限制的大小。
        //则会返回 base64 编码,否则使用 file-loader 将文件复制到输出的目录中
        test: /\.(jpe?g|png|gif)$/i,
        use: [
          {
            loader: "url-loader",
            options: {
              limit: 4096,
              fallback: {
                loader: "file-loader",
                options: {
                  esModule: false, //html-loader可以解析img的src图片
                  name: "[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]",
                },
              },
            },
          },
        ],
      },
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components)/,
        use: {
          loader: "babel-loader",
          options: {
            presets: [
              "@babel/preset-env",
             
            ],
            //路由懒加载
            plugins: ["@babel/plugin-syntax-dynamic-import"],
          },
        },
      },
     
    ],
  },
  resolve: {
    alias: {
      vue$: "vue/dist/vue.runtime.esm.js",
    },
    extensions: [".js", ".vue"],
  },

  plugins: [
    new HtmlWebpackPlugin({
      //要打包的文件
      template: path.resolve(__dirname,'../public/index.html' ),
  
   }),
    new VueLoaderPlugin(),
    new CleanWebpackPlugin("dist", {
      root: path.resolve(__dirname, "../"),
    }),  
    new BundleAnalyzerPlugin(),
    //拷贝资源文件
    new CopyPlugin([
      {
      from: path.resolve(__dirname, "../src", "assets"), 
      to: path.resolve(__dirname, "../dist", "assets")
      }
    ],
    ),
    //
  ],
};
6.3 webpack.dev.config.js
const webpack = require('webpack');
const merge=require('webpack-merge');
const common=require('./webpack.config')
//开发环境配置
module.exports =merge(common,{

    devtool:'eval-cheap-module-source-map',
    module:{
        rules:[
            {
                //匹配以.scss结尾的文件
                test: /\.scss$/,
                //使用哪个加载器,这边顺序不能乱。
                use: [
                  "style-loader",
                  {
                    loader: "css-loader",
                    options: {
                      sourceMap: true,
                    },
                  },
                  {
                    loader: "sass-loader",
                    options: {
                     
                      // Prefer `dart-sass`
                      implementation: require("sass"),
                    },
                  },
                  {
                    loader: "postcss-loader",
                    options: {
                      sourceMap: true,
                        plugins: 
                          [
                            require('autoprefixer'),
                          
                        ],
                    
                  },
                }
                ],
              }
        ]
    },
    plugins:[
      //热更新模块插件
    new webpack.HotModuleReplacementPlugin(),
    new webpack.DefinePlugin({
        APP_BASE_URL:JSON.stringify('http://localhost:3003')
    })
    ],
}) 
6.3 webpack.prod.config.js

const MiniCssExtractPlugin = require(“mini-css-extract-plugin”);
const CssMinimizerPlugin = require(“css-minimizer-webpack-plugin”);
let merge=require(‘webpack-merge’);
let common=require(’./webpack.config’)
//生产环境配置

module.exports =merge(common,{
    devtool:'source-map',
    module:{
        rules:[
            {
            //匹配以.scss结尾的文件
            test: /\.scss$/,
            //使用哪个加载器,这边顺序不能乱。
            use: [
                MiniCssExtractPlugin.loader,
              {
                loader: "css-loader",
                options: {
                  //Allows to enables/disables or setups number of loaders applied before CSS loader
                  // 0 => no loaders (default);
                  // 1 => postcss-loader;
                  // 2 => postcss-loader, sass-loader
                  importLoaders: 2,
                },
              },
              {
                loader: "sass-loader",
                options: {
                  // Prefer `dart-sass`
                  implementation: require("sass"),
                },
              },
              {
                loader: "postcss-loader",
                options: {
                  postcssOptions: {
                    plugins: [
                      [
                        "autoprefixer",
                        {
                          // Options
                        },
                      ],
                    ],
                  },
                },
              },
            ],
          },]
    },
    plugins:[
        //打包css插件
        new MiniCssExtractPlugin({
            filename: 'assets/css/[name].[contenthash:8].css',
            chunkFilename: 'assets/css/[name].[contenthash:8].css'
        }  
        ),
    ],
      //css优化压缩插件
  optimization: {
    minimize: true,
    minimizer: [
      new CssMinimizerPlugin({
        minimizerOptions: {
          preset: [
            "default",
            {
              //删除注释
              discardComments: { removeAll: true },
            },
          ],
        },
      }),
    ],
  },
    
}) 

7 集成VueRouter,Vuex

先安装依赖文件
npm install vue-router vuex --save
7.1 集成VueRouter
新增视图组件 在 src 目录下新增两个视图组件 src/views/Home.vue 和 src/views/About.vue

webpack4搭建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>

About.vue大致一样,更换下Home->About,

新增路由配置文件
	// 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: '*',
      redirect: '/Home'
    }
  ]
})
修改main.js
// main.js
import Vue from 'vue'
import App from './App.vue'
import router from './router'

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')
修改App.vue
// App.vue
// 在 template 中添加
// src/App.vue
<template>
  <div class="App">
    Hello World
  </div>
  <div>
      // router-link 组件 用来导航到哪个路由
      <router-link to="/Home">go Home</router-link>
      <router-link to="/About">go About</router-link>
    </div>
    <div>
      // 用于展示匹配到的路由视图组件
      <router-view></router-view>
    </div>
</template>

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

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

<style lang="scss" scoped>
.App {
  color: skyblue;
}
</style>

运行 npm run start
webpack4搭建vue开发环境
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fpYESlOF-1628257162283)(https://imgblog.csdnimg.cn/92b5108bc54e42c593b00c801ae5b083.gif#pic_center)]

7.2 集成Vuex
在src下新建/store/index.js
// 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
})
修改 main.js 文件 导入 vuex
	// 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')
修改 App.vue ,查看 vuex 配置效果
// 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>

webpack4搭建vue开发环境

8 总结

1.package.json里的包老是有兼容性问题,这个问题是完成这次任务90%的障碍,不要默认安装最新的版本,去npm
找低一点的版本安装.
2.把package.json的里各种依赖包后面的^删除,定死版本,否则下次npm install,大概率报错.
3.要有耐心,出错别怕,多找相似原因,多google,*,百度...

最后放上代码地址,供大家参考

https://gitee.com/httpxiaobocom/vuecli.git

参考文章 :https://juejin.cn/post/6844903833160646663#heading-22
上一篇:webpack4:处理css文件


下一篇:Webpack4(三)