如何在 vue2.0 中从 0 - 1 配置 webpack4.0

前言

  • 最近掘金上关于webpack的文章像是开了挂通常,疯狂的产出量着实让人望洋兴叹。这不,我这麽懒的人也都来凑个热闹,嘿嘿(黑人头像)!
  • 先大概说下下来到底干神马。本文默认你已经看过webpack官方文档或者一些基础的文章资料,说实话这方面的优质文章太多了,做为一个前端菜鸟的我就不在这里重复造轮子了,若是您还非要再去看下,得嘞,看官您这边请:从0到1教你撸一撸webpack深刻浅出Webpackwebpack中文文档。那咱干啥呢,请看标题【如何在vue2.0中配置webpack4.0】,对,就是这样的,咱们手牵手从无到有在vue2.0来配置起webpack4.0,话很少说,走起!

基础构建

初始化环境依赖

首先咱们新建一个项目webpack-vue-demo,而后npm initnpm init -y初始化项目,会在根目录生成一个package.json文件,打开package.json瞅一眼,除了一些基础信息,啥也没有,别慌,没有就对了,这才称得上从无到有嘛。既然是在vue中配置webpack那项目确定得要有vue环境和webpack环境,咱们这里就都采用本地安装(安装依赖)的方式,经过两行命令来搞定:css

npm i -S vue
npm i -D  vue-loader vue-style-loader vue-template-compiler
复制代码
  • vue-loader
    官方文档解释是vue-loader 是一个 webpackloader,它容许你以一种名为单文件组件 (SFCs)的格式撰写 Vue 组件。这也就是vue中能够.vue文件的方式写组件的缘由。vue-loader会将.vue的组件识别成三部分templatescriptstyle而后再经过webpack配置中的其余相关loader将其完全解析成浏览器可识别的htmljscss文件。
  • vue-style-loader
    用于处理vue-loader解析后的style
  • vue-template-compiler
    把 vue-loader 提取出的 HTML 模版编译成对应的可执行的 JavaScript 代码。
npm i -D  webpack webpack-cli
复制代码

这里须要注意的是从webpack4.0开始,webpackcli 被分红了两个包,所以咱们须要分别安装这两个依赖才能够,不然在控制台会输出提示安装webpack-cli,固然缺乏也是打包不成功的。html

至此,咱们的两个必要的环境依赖安装好了,下来咱们将项目的基础目录和相关基础文件搞起来。前端

构建基础目录

项目根目录下建立src文件夹,index.htmlwebpack.config.jswebpackfile.js(webpack配置文件,全部的webapck配置都在这里进行),在src下又分别建立index.js, views文件夹等项目所需文件,具体参考效果以下:vue

webpack-vue-demo(项目根目录)

—— src(项目源代码目录)
    —— index.js(项目打包入口文件)
    —— views(页面组件)
        —— App.vue(项目根组件)
    —— assets(图片资源目录,存放图片)
    —— components(公共组件目录)
        —— child.vue(子组件)
    —— styles(公共样式目录,存放公共,全局等一些样式表)
—— index.html(html模板)
—— webpack.config.js/webpackfile.js(webpack配置文件)
—— package.json(包管理文件)
复制代码

初始化vue(实例化,挂载等)

这部分没啥好说的,直接贴代码吧node

<!--App.vue-->
<template> <div id="app"> <Child></Child> </div> </template>

<script>
import Child from "@/components/child"; //这里可使用@符号,是须要在webpack配置文件里面配置,后面会说到,先这样写。
export default {
  name: "App",
  data() {
    return {};
  },
  components: {
    Child
  }
};
</script>

<style scoped>
</style>
复制代码
<!--index.js-->
import Vue from 'vue'
import App from './views/App'


new Vue({
    el:'#app',
    render: h => h(App)
})
复制代码

到此,项目基础工做已经基本落地完成,下来咱们就来专一作配置的事情(这里项目还运行不起来,由于尚未webpack配置)。webpack

配置 webpack(version-1)

在配置以前,咱们先稍微补充点点额外的。
git

第一:咱们在启动或者打包vue项目的时候都是使用npm run devnpm run build这样的命令来完成的,而这样的命令则是在package.json里的scripts中定义的。因此那到底这是为何呢,为啥这里定义后就能够启动webpack打包任务呢?es6

  • package.json 里面定义的scripts字段(对象)是Npm Script的一种表现形式,也就是说Npm Script容许在package.json 文件里面使用scripts字段定义任务,而Npm Script自己就是Npm内置的一个功能,专门用来执行任务的。因此在 package.jsonscripts对象里定义的每个任务都是一个npm可执行的任务。这些任务每个对应一段 Shell 脚本,例如定义的 devbuild, 其底层实现原理都是经过调用 Shell 去运行脚本命令,执行 npm run build 命令等同于执行命令 node build.js。又webpack在执行打包压缩的时候是依赖nodejs, so,应该明白了吧!执行Npm Script任务就能够启动webpack打包压缩程序。

第二:配置 Webpack 的方式有两种:github

  1. 经过一个 JavaScript 文件描述配置,例如使用 webpack.config.js 文件里的配置;
  2. 执行 Webpack 可执行文件时经过命令行参数传入,例如 webpack --devtool source-map

这两种方式能够相互搭配,例如执行 Webpack 时经过命令 webpack --config webpack.config.js 指定配置文件,再去 webpack.config.js 文件里描述部分配置。可是只经过命令行参数传入的选项,这种最为少见;顺势而为,咱们该项目中会采用两种结合的方式。不过主要的配置都在webpack.config.js文件里面进行。
web

下面就开始吧!

Entry

entry: 必填项,配置入口文件的名称,为string 类型。若是只有一个入口文件,则能够把它写成静态不变的,Webpack 执行构建的第一步将从入口开始搜寻及递归解析出全部入口依赖的模块。(执行打包压缩的入口)

<!--webpack.config.js-->
module.exports = {
    entry: "./src/index.js"
}
复制代码

Output

output:必填项,配置如何输出最终想要的代码的出口,是一个对象,经常使用的属性filename(指定导出文件名)、path(配置输出文件存放在本地的目录,必须是 string 类型的绝对路径。一般经过 Node.jspath 模块去获取绝对路径)

  • Tip:在配置文件中可能会很频繁遇到path.resolve(__dirname, "xxx")的语法,这个语法是 node.jspath模块提供的一个绝对路径解析的方法,若是想要深刻了解,能够去查看 node.js文档,咱们这里只需知道它的做用就行。固然在使用的文件中须要手动在文件顶部require进来才可使用的。
<!--webpack.config.js-->
const path = require("path"); //node.js 里面的path模块,这里用来解析绝对路径的
module.exports = {
    entry: "./src/index.js", //指定入口文件
    output: {
        filename: "[name].[hash].js", //导出的文件名,hash值是避免文件名缓存
        path: path.resolve(__dirname, "dist") //导出的打包后文件输出路径(必须是绝对路径)
    },
}
复制代码

Loader

loader:必填项,模块转换器,能够理解为一个将非js模块翻译为js模块的具备文件转换功能的翻译员。由于webpack在进行模块打包构建时只识别js模块文件,那对于非js的类型文件须要将其进行转换成js类型,这就是咱们项目中为啥能够正常使用图片,视频以及样式预处理器等的缘由,它们都会对应有不一样的loader来对其进行翻译转换,固然这些loader是须要配置才能够生效的。

  • module:模块,webpack中一切皆模块(任何文件都看做是一个模块)
  • rules:配置模块的读取和解析规则,一般用来配置Loader。其类型是一个数组,数组里每一项都描述了如何去处理部分文件
  • test、include、exclude:text (指定应用当前 loader 的类型文件,这里就是全部 .css 后缀的文件都应用css-loader来处理),include(指定去查找的目录),exclude (排除不须要查找的目录),通常 includeexclude二选一结合 test使用。是缩小查询范围的一种优化手段。
  • use: 配置应用的loader,能够是字符串、数组、对象
  • loader:模块解析器,能够是字符串、数组、对象。
const path = require("path"); //node.js 里面的path模块,这里用来解析绝对路径的

module.exports = {
  entry: "./src/index.js", //指定入口文件
  output: {
    filename: "[name].[hash].js", //打包导出文件的文件名
    path: path.resolve(__dirname, "dist") //导出的打包后文件输出路径(必须是绝对路径)
  },
  
  module: {
    rules: [
      {
        test: /\.css$/,//指定应用当前loader的类型文件,这里就是全部.css后缀的文件都应用css-loader来解析
        use: [ "vue-style-loader", "css-loader"]
      },
      {
        test: /\.scss/,
        use: ["vue-style-loader""css-loader""sass-loader"]
      },
      {
        test: /\.(png|jpg|gif|svg|bmp)$/,
        use: {
          loader: "url-loader",
          options: {
            esModule: false,
            limit: 10 * 1024, //限制图片资源大小,小于10kb的图片会以 base64 编码输出,大于此限制值的会以拷贝方式(file-loader)放到 'outputPath'指定目录下
            outputPath: "imgs/" //指定图片资源输出路径,不指定默认直接放到dist目录下,此时这里是 dist/imgs/
          }
        }
      },
      {
        test: /\.js$/,
        loader: "babel-loader",
        exclude: /node_modules/ //不查找 'node_modules'目录
      },
      {
        test: /\.vue$/,
        use: "vue-loader"
      }
    ]
  }
};
复制代码

关于 loader,需特别注意 的是,若配置一组 loader,那么组内的 loader 是有严格的执行顺序的,不可颠倒。顺序为按照数组索引反方向(从尾部往头部)依次执行,并将当前 loader 解析结果传递给后一个loader去解析,在最后一个 loader,返回 webpack 所预期的 JavaScript

  • vue-style-loader

    • 安装:npm i -D vue-style-loader
    • 描述:功能相似于 style-loader,是将 css-loader 加载后的 css做为样式标签动态注入到文档中,是专门应用于 vue 模板环境下的样式表加载器。所以若是配置了 vue-style-loader 就不须要再配置 style-loader了。
  • css-loader

    • 安装:npm i -D css-loader
    • 描述:解释 @import 和 url() ,会 import/require() 后再解析它们。通俗的讲就是 css-loader 会找出当前 css 文件中的 @importurl() 这样的导入语句,告诉 Webpack 依赖这些资源,而后同时将当前 css文件 解析成模块,处理完后再把结果交给 style-loader 去处理。
  • sass-loader

    • 安装:npm i -D sass-loader
    • 描述:sass-loader 的做用就是把 scss 源码转换为 css 代码,再把 css 代码交给 css-loader 去处理。
  • url-loader

    • 安装:npm i -D url-loader
    • 描述
      • 能够把文件的内容通过 base64 编码后注入到 JavaScript(模板中或js中引入) 或者 css(css中引入) 中去,通常用来加载解析图片、视频等媒体资源,但一般是处理比较小的媒体资源,例如图片,将解析后的资源注入到代码中去,但由于是采用 base64编码后,所以会形成代码文件过大,因此,一般会配合 limit属性一块儿使用,当超过当前 limit限制,则采用 file-loader加载解析,将资源进行拷贝。这里还有两个属性值得注意,通常须要配合使用。
      • esModule:默认为 true,表示文件加载器会生成使用 ES 模块语法的 JS 模块,若是关闭(false),则采用 CommonJS模块语法来生成 JS 模块,这里必定要为 false,是踩坑发现的,若是不关闭,则 采用 require方式引入的模块资源打包后不能正常显示。
      • outputPath:指定图片资源输出路径,不指定默认直接放到dist目录下。
  • babel-loader

    • 安装:npm i -D @babel/core @babel/plugin-transform-runtime @babel/preset-env babel-loader
    • 描述
      • Babel 是一个 JavaScript 编译器,能将采用 ES6ES7 甚至更高规范的代码转为 ES5 规范下的代码。为啥转换嘞,由于浏览器的支持性很差。那在项目使用过程当中 一般采用配置 loader + 插件 的形式来转换 js 代码,这里的 loader也就是 babel-loader。须要注意下,由于 babel-loader 执行比较耗时,所以使用exclude去排除无需查找的目录,好比 node_modules,不然默认会查找全部目录下符合要求的文件。
      • babel-plugin-transform-runtimeBabel 官方提供的一个插件,做用是减小冗余代码。 Babel 在把 ES6 代码转换成 ES5 代码时一般须要一些 ES5 写的辅助函数来完成新语法的实现。babel-plugin-transform-runtime 的做用在于不把辅助函数内容注入到文件里。
      • presets 属性告诉 Babel 要转换的源码使用了哪些新的语法特性,一个 Presets 对一组新语法特性提供支持,多个 Presets 能够叠加。 Presets 实际上是一组 Plugins 的集合,每个 Plugin 完成一个新语法的转换工做
      • Babel 执行编译的过程当中,会从项目根目录下的 .babelrc 文件读取配置。.babelrc 是一个 JSON 格式的文件,因此须要在项目根目录新建一个 .babelrc文件
      <!--.babelrc-->
      {
          "presets": ["@babel/preset-env"],//设定转码规则
          "plugins": ["@babel/plugin-transform-runtime"] // transform-runtime 插件表示无论浏览器是否支持ES6,只要是ES6的语法,它都会进行转码成ES5
      }
      复制代码
  • vue-loader

    • 安装:npm i -D vue vue-loader vue-style-loader vue-template-compiler
    • Tip:该 loader 的安装每每会结合 vue一块儿安装。
    • 描述:文章开头已经描述,这里就再也不重复说明。

至此,项目中经常使用到的 loader 就已经所有安装及说明完毕,可能心急的小伙伴已经火烧眉毛想试试看一下效果,可是,这会还真不行,还差一个重要的配置项 插件 (plugin),因此咱们还得再往下继续看看。

Plugin

plugin:必填项 ,插件是 webpack 的支柱功能,用于扩展 Webpack 的能力,在 webpack 的构建流程中,plugin 用于处理更多其余的一些构建任务,只要是loader没法实现的事,插件均可以完美的胜任。所以其地位和做用不言而喻,称得上是webpack中最重要的配置。格式是数组,数组中的每一项都是用来行使不一样目的的插件实例(new)。

const path = require("path"); //node.js 里面的path模块,这里用来解析绝对路径的
const HtmlWebpackPlugin = require("html-webpack-plugin"); //自动生成html
const VueLoaderPlugin = require("vue-loader/lib/plugin"); //必须导入此插件,它负责克隆您定义的任何其余规则,并将它们应用于.vue文件中的相应语言块
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //分离css

module.exports = {
  ...
  plugins: [
    new VueLoaderPlugin(),
    new HtmlWebpackPlugin({
      template: "./index.html", //模板文件
      filename: "index.html", //文件名
      hash: true //避免缓存
    }),
    new MiniCssExtractPlugin({
      filename: "styles/[name].[hash].css", //指定分离生成的css文件名,hash为了不缓存
    })
  ]
};

复制代码
  • vue-loader-plugin
    • 安装:在安装 vue-loader的时候会生成
    • 描述:将你定义过的其它规则复制并应用到 .vue 文件里相应语言的块。例如,若是你有一条匹配 /\.js$/ 的规则,那么它会应用到 .vue 文件里的 <script> 块。
  • html-webpack-plugin
    • 安装:npm install -D html-webpack-plugin
    • 描述:该插件会自动生成一个 HTML5 文件, 其中包括使用 script 标签的 body 中的全部 webpack 包,所以咱们无需担忧打包后的全部依赖,它会帮咱们自动引入 html 模板中,例如(js,css),解放了双手。
      • template: 这里须要咱们提早定义好一个 html模板文件,template 属性就是用来指定所使用的模板文件
      • filename: 是指定产出后的文件名,就是 dist目录下的那个 html文件名。
      • hash:避免文件缓存
  • mini-css-extract-plugin
    • 安装:npm install -D mini-css-extract-plugin
    • 描述:
      • 该插件主要做用用来分离 css 代码,咱们的 css 代码在通过 css-loader,style-loder解析后以字符串的形式存在于js文件中。这样随着项目的业务扩展,会致使当前js文件会愈来愈大,而且也会加载的很慢,因此咱们这里使用 mini-css-extract-plugin来将每个 js 文件中的 css代码单独分离出来,而且支持异步、按需加载。
      • 该插件的配置方式跟其他插件略有不一样,除了在 plugins数组里注册外,还须要将 style-loadervue-style-loader替换成以下的写法:
        <!--webpack.config.js-->
        
          module: {
            rules: [
              {
               ...
                use: [
                  {
                    loader: MiniCssExtractPlugin.loader //分离css
                  },
                  "css-loader"
                ]
              },
              {
              ...
                use: [
                  {
                    loader: MiniCssExtractPlugin.loader
                  },
                  "css-loader",
                  "sass-loader"
                ]
              },
            ]
        }
        复制代码

到这里,项目就能够进行打包了。只不过咱们须要在 package.jsonscript属性中定义下任务命令就行了。

<!--package.json-->
...
"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack --mode development",//开发环境下打包命令
    "build": "webpack --mode production"//生产环境下打包命令
  },
复制代码

ok,控制台运行命令 npm run devnpm run build会发如今项目根目录产生一个 dist文件夹,dist 文件夹下就是 webpack打包后的源代码,咱们能够编辑器打开 index.html瞅一眼会发现多了一个 <link><script>标签,这就是上面提到的 html-webpack-plugin插件帮咱们完成的。而后浏览器运行 index.html 文件,会发现有内容,而且正是咱们开始在child.vue 组件里定义的东西。此时就说明打包已经成功。
也许,此时的你正沉浸在喜悦中没法自拔,但是,这并非咱们想要的结果。试想下 vue-cli中打包项目的时候是如何的一个情景,而且当咱们更改代码的时候的热更新又是如何的一个情景,因此,还须要优化。首先先整理下须要实现的几个效果

  1. 本地能够运行项目,支持代码热更新、热替换
  2. 项目运行或者打包能够看到进度条。

好了,明确需求后,咱们就来实现它。仍是先贴出代码,再叙述实现吧。

<!--webpack.config.js-->
...
const webpack = require("webpack"); 
const ProgressBarPlugin  = require("progress-bar-webpack-plugin") //运行/打包,显示进度条

module.exports = {
...
  devServer: {
    host: 'localhost',//开发服务器监听的主机地址
    port: 8000, //开发服务器监听的端口号,默认是 8080
    compress: true, //启用压缩
  },
  
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new ProgressBarPlugin()
  ]
};

复制代码
  • webpack-dev-server

    • 安装:npm i -D webpack-dev-server

    • 描述:

      • 使用 DevServer会帮咱们在本地启动一个服务,这样咱们能够经过在浏览器访问服务地址来预览效果,而不用每次手动去打开 index.html 文件。
      • DevServer 它提供了一些配置项能够改变 DevServer 的默认行为。 要配置DevServer ,除了在配置文件里经过 devServer 传入参数外,还能够经过命令行参数传入。 注意只有在经过 DevServer 去启动 Webpack 时配置文件里 devServer 才会生效,由于这些参数所对应的功能都是 DevServer 提供的,Webpack 自己并不认识 devServer 配置项。
      <!--webpack.config.js-->
      module.exports = {
      ...
        devServer: {
          host: 'localhost',//开发服务器监听的主机地址
          port: 8000, //开发服务器监听的端口号,默认是 8080
          compress: true, //启用压缩
        }
      };
      复制代码

      若是使用了命令行参数,则启动服务时会将参数写入devServer配置中,若是有重名,则命令行参数会覆盖配置项属性。

      • DevServer使用须要在package.json里的 script属性中配置命令:
      <!--package.json-->
      "scripts": {
          "dev": "webpack-dev-server --open",
      },
      复制代码
      • webpack-dev-server 命令启动服务后运行的打包文件是在 内存中,并不在 硬盘中,为了验证这一点,你能够将dist文件夹删掉,而后重启服务,会发现并不会在项目根目录生成 dist文件夹,何况项目仍然能够运行。
  • HotModuleReplacementPlugin

    • 安装:webpack内置的插件,所以无需单独安装。
    • 描述: 该插件是用来启用热替换模块(HMR)的,启用热替换模块的好处是当咱们更改了模块文件的代码时浏览器在不刷新当前页面的状况下更新页面内容。其实实现有两种方式,除了这里的使用插件,还要就是使用命令行webpack-dev-server --hot,二者看心情任选其一便可。
  • progress-bar-webpack-plugin

    • 安装:npm i -D progress-bar-webpack-plugin
    • 描述:该插件比较简单,就是一个用来显示打包进度的插件,尤为是当项目比较大的时候,打包比较耗时,显示进度会显得体验比较友好。

那麽如今,咱们再npm run dev的时候就会在本地使用服务来运行当前项目,当修改模块中的代码,会自动热更新。并且还会有进度条,这样看起来就舒服多了吧。

Resolve

resolve:可选项,格式是对象,配置 Webpack 如何寻找模块所对应的文件。 Webpack 内置 JavaScript 模块化语法解析功能,默认会采用模块化标准里约定好的规则去寻找,但你也能够根据本身的须要修改默认的规则。修改的规则就要定义在 resolve 中,如下列出来几个比较常见的解析规则

<!--webpack.config.js-->
...
module.exports = {
    ...
    resolve: {
      extensions: [".js", ".vue", ".scss", ".css"], //后缀名自动补全,当导入文件的时候能够省略后缀名不写
      alias: {
        vue$: "vue/dist/vue.esm.js", //精确匹配,当import Vue from 'vue'的时候引入的是vue.esm.js这个版本库而不是其余版本库
        "@": path.resolve(__dirname, "../src"), //用@代替./src路径 因此就能够 import xx from ' @/xx'
    }
    }
}

复制代码

到如今,其实关于 vue2.0中配置webpack4.0的经常使用配置的知识点差很少已经说完了。那麽是时候将 webpack.config.js的总体代码 bia出来了。

<!--webpack.config.js-->
const path = require("path"); //node.js 里面的path模块,这里用来解析绝对路径的
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin"); //自动生成html
const VueLoaderPlugin = require("vue-loader/lib/plugin"); //必须导入此插件,它负责克隆您定义的任何其余规则,并将它们应用于.vue文件中的相应语言块
const MiniCssExtractPlugin = require("mini-css-extract-plugin"); //分离css
const ProgressBarPlugin  = require("progress-bar-webpack-plugin") //运行/打包,显示进度条

module.exports = {
  entry: "./src/index.js", //指定入口文件
  output: {
    filename: "[name].[hash].js", //导出的文件名
    path: path.resolve(__dirname, "dist") //导出的打包后文件输出路径(必须是绝对路径)
  },
  resolve: {
    extensions: [".js", ".vue", ".scss", ".css"], //后缀名自动补全,当导入文件的时候能够省略后缀名不写
    alias: {
      'vue$': 'vue/dist/vue.esm.js',//精确匹配,当import Vue from 'vue'的时候引入的是vue.esm.js这个版本库而不是其余版本
      "@": path.resolve(__dirname, "./src") //用@代替./src路径 因此就能够 import xx from ' @/xx'
    }
  },
  module: {
    rules: [
      {
        test: /\.css$/,//指定应用当前loader的类型文件,这里就是全部.css后缀的文件都应用css-loader来处理
        use: [
          {
            loader: MiniCssExtractPlugin.loader //分离css
          },
          "css-loader"
        ]
      },
      {
        test: /\.scss/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader
          },
          "css-loader",
          "sass-loader"
        ]
      },
      {
        test: /\.(png|jpg|gif|svg|bmp)$/,
        use: {
          loader: "url-loader",
          options: {
            esModule: false,
            limit: 10* 1024, //限制图片资源大小,小于10kb的图片会以 base64 编码输出,大于10kb的会以拷贝方式(file-loader)放到 'outputPath'指定目录下
            outputPath: "imgs/" //指定图片资源输出路径,不指定默认直接放到dist目录下,此时这里是 dist/imgs/
          }
        }
      },
      {
        test: /\.js$/,
        loader: "babel-loader",
        exclude: /node_modules/ //不查找 'node_modules'目录
      },
      {
        test: /\.vue$/, 
        use: "vue-loader"
      }
    ]
  },
  devServer: {
    host: 'localhost',//开发服务器监听的主机地址
    port: 8000, //开发服务器监听的端口号,默认是 8080
    compress: true, //启用压缩
    
  },
  plugins: [
    new VueLoaderPlugin(),
    new webpack.HotModuleReplacementPlugin(),
    new HtmlWebpackPlugin({
      template: "./index.html", //模板文件
      filename: "index.html", //文件名
      hash: true //避免缓存
    }),
    new MiniCssExtractPlugin({
      filename: "styles/[name].[hash].css",
    }),
    new ProgressBarPlugin()
  ],
  devtool: "source-map" //能够直接在浏览器控制台source下查看项目未打包的源代码,在出现一些错误的时候,
  //若是不使用source-map的时候,错误没法定位到源代码中。
  //使用了source-map之后,能够直接定位到错误出现的行
};

复制代码

同时也附上仓库源代码地址,有须要能够直接 folk vue2.0中配置webpack4.0版本1源代码地址

以上为版本1,难道还有版本2不成(黑人问号脸)?,对,确实还有版本2。卧槽,无情!


在实际开发中咱们每每会有不一样的环境,常见的就是开发环境和生产环境,根据不一样的环境,每每咱们的webpack配置是有差别的,所以就须要把不一样环境的配置从 webpack.config.js 文件中分离出来。如何分离,请继续往下看。

webpack 分环境配置(version-2)

新建配置目录

项目根目录新建 build文件夹,build目录下新建三个配置文件,分别是:webpack.base.conf.js(基础配置文件)、webpack.dev.conf.js(开发环境配置文件)、webpack.pro.conf.js(生产环境配置文件)。

分离配置

1. webpack.base.conf.js

webpack.base.conf.js 文件放置开发环境和生产环境webpack打包时候须要的公共基础配置项。

<!--webpack.base.conf.js->
const path = require("path"); //node.js 里面的path模块,用于生成绝对路径
const VueLoaderPlugin = require("vue-loader/lib/plugin"); //必须导入此插件,它负责克隆定义的任何其余规则,并将它们应用于.vue文件中的相应语言块
const CopyPlugin = require("copy-webpack-plugin");//拷贝静态文件,例如.txt,.md等文件
const MiniCssExtractPlugin = require("mini-css-extract-plugin");//分离css
const ProgressBarPlugin = require("progress-bar-webpack-plugin"); //运行/打包,显示进度条

module.exports = {
  entry: path.resolve(__dirname, "../src/index.js"), //指定入口文件
  output: {
    filename: "[name].[hash].js", //导出的文件名
    path: path.resolve(__dirname, "../dist") //导出的打包后文件输出路径(必须是绝对路径)
  },
  resolve: {
    extensions: [".js", ".vue", ".scss", ".css"], //后缀名自动补全,当导入文件的时候能够省略后缀名不写
    alias: {
      vue$: "vue/dist/vue.esm.js", //精确匹配,当import Vue from 'vue'的时候引入的是vue.esm.js这个版本库而不是其余版本
      "@": path.resolve(__dirname, "../src"), //用@代替./src路径 因此就能够 import xx from ' @/xx'
      assets: path.resolve(__dirname, "../src/assets")
    }
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader
          },
          "css-loader"
        ]
      },
      {
        test: /\.scss/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader
          },
          "css-loader",
          "sass-loader"
        ]
      },
      {
        test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
        use: {
          loader: "url-loader",
          options: {
            esModule: false,
            limit: 10 * 1024, //限制图片资源大小,小于10kb的图片会以 base64 编码输出,大于的会以拷贝方式(file-loader)放到 'outputPath'指定目录下
            outputPath: "static/imgs/" //指定图片资源输入路径,不指定默认直接放到dist目录下,此时这里是 dist/static/imgs/
          }
        }
      },
      {
        test: /\.js$/,
        loader: "babel-loader",
        exclude: /node_modules/ //不查找 'node_modules'目录
      },
      {
        test: /\.vue$/,
        use: "vue-loader"
      }
    ]
  },
  plugins: [
    new VueLoaderPlugin(),
    new MiniCssExtractPlugin({
      filename: "static/css/[name].[hash].css"
    }),
    new ProgressBarPlugin(),
    new CopyPlugin([
      {
        from: path.resolve(__dirname, "../src/static"),
        to: "static"
      }
    ])
  ]
};
复制代码
  • copy-webpack-plugin
    • 安装:npm run copy-webpack-plugin -D
    • 描述:
      • 这里新增了一个插件,copy-webpack-plugin,就是将既不是 js ,也不是 css图片 之类的静态文件,好比 README.md,也但愿能打包到个人项目里,而这个插件就是采用拷贝的方式来将其复制进咱们的打包目录。
      • from:须要拷贝的静态文件源路径
      • to:文件拷贝后输出的目标位置。
2. webpack.dev.conf.js

webpack.dev.conf.js 文件仅存放开发环境下 webpack打包时候/运行项目的 webpack 配置项。依然先 bia 代码,再进行说明。

const path = require("path");
const merge = require("webpack-merge");//合并配置项的方法
const base = require("./webpack.base.conf");//基础配置项
const webpack = require("webpack");
const HtmlWebpackPlugin = require("html-webpack-plugin"); //自动生成html
const FriendlyErrorsPlugin = require("friendly-errors-webpack-plugin"); //能够识别某些类的webpack错误,并清除,汇总并肯定优先级。

const devWebpackConfig = merge(base, {
  mode: "development",
  devtool: "source-map",
  devServer: {
    host: "localhost", //用于配置 DevServer 服务监听的地址,想要局域网中的其它设备访问你本地的服务,请配置为 0.0.0.0,默认只有本地能够访问
    port: 8000, //访问端口号,默认8080,若是被占用,会自动更换
    quiet: true, // necessary for FriendlyErrorsPlugin
    compress: true, //启用压缩
    open: false //自动打开浏览器
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(), //模块热替换,当更新代码时候自动编译,无需手动更新,通常配合webpack-dev-server 使用

    new HtmlWebpackPlugin({
      template: "./index.html", //模板文件
      filename: "index.html", //文件名
      inject: true // true || 'head' || 'body' || false,注入资源到给定的html模板文件,若是为true或者body,则将全部js文件都将放置在body元素的底部
    })
  ],
  devtool: "source-map" //在浏览器端调试方便,能够直接看源码
});

module.exports = new Promise(resolve => {
  const host = devWebpackConfig.devServer.host;
  const port = devWebpackConfig.devServer.port;
  devWebpackConfig.plugins.push(
    new FriendlyErrorsPlugin({
      compilationSuccessInfo: {
        messages: [`Your application is running here: http://${host}:${port}`]
      },
      onErrors: function(severity, errors) {
        // You can listen to errors transformed and prioritized by the plugin
        // severity can be 'error' or 'warning'
      }
    })
  );
  resolve(devWebpackConfig);
});

复制代码
  • webpack-merge

    • 安装:webpack内置,所以无需单独安装。
    • 描述:webpack-mergewebpack提供的一个能够合并对象/数组并生成新的对象的方法。所以咱们这里能够借助该方法,将 webpack.base.conf.js暴露的基础配置对象合并进来。
  • friendly-errors-webpack-plugin

    • 安装: npm i -D friendly-errors-webpack-plugin
    • 描述:
      • 能够识别某些类的webpack错误,并清除,汇总并肯定优先级。简单讲,就是一个捕获并收集打包编译过程当中发生的错误,并给出提示的插件。这里咱们用它来在编辑器控制台显示当前项目在浏览器端的访问地址(vue-cli中那样)
        例如:


      • 配置该插件时候须要注意两点:

        1. 为了引用到当前文件中配置的主机号和端口号,所以须要改写下 module.exports 导出配置的写法,这里咱们使用导出 Promise 对象,具体使用请看上方的代码。或者参考官方文档。
        2. 除了须要在 plugins里注册实例,还需在 devServer 里面添加 quiet: true,固定用法。
3. webpack.pro.conf.js

webpack.pro.conf.js 文件仅存放生产环境下 webpack打包时候的 webpack 配置项。依然先 bia 代码,再进行说明。

const path = require("path");
const merge = require("webpack-merge"); //合并webpack options
const base = require("./webpack.base.conf");
const HtmlWebpackPlugin = require("html-webpack-plugin"); //自动生成html
const TerserPlugin = require("terser-webpack-plugin"); //压缩js
const OptimizeCSSPlugin = require("optimize-css-assets-webpack-plugin");//压缩css
const { CleanWebpackPlugin } = require("clean-webpack-plugin"); //每次打包前,先清理掉以前的打包文件

module.exports = merge(base, {
  mode: "production",
  optimization: {
    minimize: true,
    minimizer: [new TerserPlugin()],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: "./index.html", //模板文件
      filename: "index.html", //文件名
      inject: true, // true || 'head' || 'body' || false,注入资源到给定的html模板文件,若是为true或者body,则将全部js文件都将放置在body元素的底部
      favicon: path.resolve(__dirname,'../favicon.ico'),
      //若是将minify选项设置为true(当webpack的模式为“生产”时为默认值),则将如下选项来缩小生成的HTML(压缩html资源)
      minify: {
        removeComments: true, //移除注释
        collapseWhitespace: true, //合并空格
        removeAttributeQuotes: true //移除属性双引号
      }
    }),
    new OptimizeCSSPlugin({
      assetNameRegExp: /\.css$/g,
      cssProcessor: require("cssnano")
    }),
    new CleanWebpackPlugin()
  ]
});

复制代码
  • terser-webpack-plugin

    • 安装:npm i -D terser-webpack-plugin

    • 描述:

      • 该插件用来压缩 js 代码,使用它而舍弃 uglifyjs-webpack-plugin 插件的最大一个缘由就是支持 es6 语法,而 ``uglifyjs-webpack-plugin`不支持,对就是这么任性。
      • 该插件的配置方式有点特别,不是注册在 plugins中,而是在 optimization中,关于 optimization,看官方文档的描述为优化,是一个对象,而后对象里面能够手动配置重写一些优化项和策略。感受比较高深,我就浅尝辄止,将TerserPlugin插件相关的优化项写进来。
      <!--webpack.pro.conf.js-->
       optimization: {
          minimize: true, //告知 webpack 使用 TerserPlugin 压缩 打包后的js文件
          minimizer: [new TerserPlugin()], //容许经过提供一个或多个定制过的 TerserPlugin 实例,覆盖默认压缩工具(minimizer)。
      },
      复制代码
  • optimize-css-assets-webpack-plugin

    • 安装:npm i -D optimize-css-assets-webpack-plugin
    • 描述:
      • 优化/压缩 css 的插件,使用该插件不只压缩出来的 css 拥有很好的格式,并且压缩过程当中采用的多种优化策略来保证 css 文件体积尽可能的小
      • assetNameRegExp:指定要压缩优化那种类型的静态资源文件(正则表达式)
      • cssProcessor:指定压缩优化 css 文件时采用的那种 css 处理器,默认为 cssnano
  • clean-webpack-plugin

    • 安装:npm i -D clean-webpack-plugin
    • 描述:
      • 该插件用于删除/清理构建文件夹(dist),能够对比下该插件使用先后 dist 目录下文件差别,会发现安装前屡次打包后 dist 目录下会保留每次打包生成的构建文件,那这样就带来一个问题,虽然咱们打包次数的增长,若不手动删除dist会愈来愈大。这确定不是咱们想要的。所以使用该插件能够帮咱们每一次从新打包前删除先前的构建文件夹。
      • 该插件的引入略有点特殊 const { CleanWebpackPlugin } = require("clean-webpack-plugin");,固定用法,了解便可。

还记得咱们 package.json script属性里面的任务命令吗?对,这里如今得更改下就能够起飞了。

<!--package.json-->
...
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server --config ./build/webpack.dev.conf.js",
    "build": "webpack --config ./build/webpack.pro.conf.js"
  },
  ...
复制代码

npm run devnpm run build 操做起来,看看此时构建过程跟构建后的文件跟以前有啥不一样呢? 嘿嘿嘿!。

相信能坚持看到这里的老铁绝对是真爱,因此若是您以为对你有帮助或者心里有些许波澜,麻烦给小弟 点个赞star~下,蟹蟹!

最后附上版本2的仓库源代码地址,有须要能够直接 folk vue2.0中配置webpack4.0版本2源代码地址

后记

以上就是在 vue2.0 中从 0 - 1 配置 webpack的所有内容了,webpack4.0的东西很是之多,也很是之高深,做为一个前端菜鸟深知须要学习和进步的空间还很大,所以,如如有 不恰当/不许确 之处,还望路过的各位大佬多多指教。不胜感激!

相关文章
相关标签/搜索