webpack-vue脚手架之build篇

2,587 阅读11分钟

引言

这个是作者的webpack配置相关的第一篇,所以本篇幅可能会有点长,如果你可以耐心的看完相信对于你来说也会有一定的收获,对于各位大佬而言,如果看到本文用词,或者想法思维不正确的地方,希望能够评论教导本人,感谢~

开始

创建文件夹

首先我们先来创建一个文件夹来承载我们的脚手架,我们在命令行里面输入 mkdir webpack4-vue创建文件夹,然后 cd webpack4-vue进入文件(windows的同学命令可能不太一样,我这个是mac的系统,windows的同学自己加油)。

然后通过npm init进行初始化,填写完相关配置后我们会在初始化的文件夹下面,后我们会得到一个packjson.json文件,里面大致如下:

{
  "name": "webpack4-vue",
  "version": "1.0.0",
  "description": "一个简单DEMO,使用webpack4去配置一个vue的脚手架",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "fyfy",
  "license": "ISC"
}

webpack

第一步我们来引入webpack,根据官方文档 我们分别需要安装webpack跟webpack-cli

npm install --save-dev webpack
npm install --save-dev webpack-cli

成功安装依赖之后呢,我们先来自己创建一个简单的配置文件webpack.config.js把一个简单的js来进行打包吧,在根目录下创建webpack.config.js文件写入如下配置

module.exports = {
  // 表示开发模式
  mode: 'development',
  // 文件的入口(就是我们要打包的文件)
  entry: path.resolve(__dirname, './src/main.js'),
  // 文件的出口也就是我们要生成的文件
  output: {
    // 这里[name]就是entry是什么名字的就是啥名字啦
    filename: '[name].js',
    path: path.resolve(__dirname, './dist')
  }
}

配置文件编写完之后呢,我们需要在packjson.json添加如下命令,表示使用config配置文件来完成后续的webpack打包,cli这一块更多的细节,感兴趣的小伙伴可以点击这里查看文档

{
  ...
  "scripts": {
  	// 增加一个打包命令
    "build": "webpack --config webpack.config.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  ...
}

接着我们创建/src/main.js文件并且写入下面内容

import Vue from 'vue'

new Vue({
  el: '#app',
  template: `<div>{{text}}</div>`,
  data() {
    return {
      text: '你好webpack4-vue'
    }
  }
})

并且安装依赖npm install vue,接着我们在跟文件夹下创建index.html文件,并写入下方内容

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
  </head>
  <body>
    <div id="app"></div>
    <script src="./dist/main.js"></script>
  </body>
</html>

然后运行npm run build, 提示编译成功~,然后兴奋的双击打开index.html,发现text并没有渲染出来,打开chrome的控制台发现报错了,提示如下~ chrome报错 在Vue的官方文档中一波搜索后得到以下的结论,首先我们打开node_modules/vue/package.json看到下面这块

{
  ...
    "main": "dist/vue.runtime.common.js",
    "module": "dist/vue.runtime.esm.js",
  ...
}

然后我们这边看到modulemain两个字段(为啥要看两个不同的字段,感兴趣的小伙伴可以自行百度哈)暴露的包均是vue.runtime.**.js,我们在来到Vue官方文档中找到安装-对不同构建版本的解释的这个表格 Vue版本表格 得出结论是目前npm包对外默认暴露的版本是只包含运行版本这个版本跟完整版的区别是什么呢? 版本差异 那么很明显目前来说我们还没有引入vue-loader或者是vueify,所以根据文档所得出的结论我们想让我们的main.js中的代码可以执行的下去。我们目前的条件下,就必须引入完整版本~,引入完整版本的话我们需要在webpack.config.js中添加如下配置项

// ...
resolve: {
  alias: {
    'vue$': 'vue/dist/vue.esm.js' 
  }
}
// ...

然后再次运行我们的打包命令npm run build,打包成功后,双击打开index.html查看网页情况 运行结果 nice!到这里我们就完成了最最最最最简单的一个vue的“webpack脚手架工具”啦~

babel-loader

既然我们初版的东西出来了,那么我们来装装x使用一下当下最流行的ES6吧。但是~在考虑使用ES6的情况下,我们就要去考虑我们该X的兼容性问题。比如经常会使用的来声明常量的const语句他的兼容性是怎么样的呢,我们打开caniuse看看兼容的情况吧~

caniuse截图

OK! 我们的IE又开始出来捣乱了,那我们怎么办呢?不用ES6以及之后的标准了吗?这肯定是不可能的,这个时候就要引入Babel这个工具链。

Babel

首先,我们先来看一下Babel是什么,我们来看看官方的介绍~

babel官网截图 介绍已经讲的比较清晰,相当于就是把ES6及以上的转换成ES5或者ES3的内容。目前来说呢,经过在下的一番检索以及学习,目前主要会见到的名词会有下面列出来的这么几个

我们一个个来学习一下具体的作用,以及如果多个工具在可以共同使用的环境下的优缺点~

@babel/polyfill

官方文档很直接的支持指出,使用@babel/polyfill基本全等于以下这段代码段

import 'core-js/stable';
import 'regenerator-runtime/runtime';

那么我们这里首先需要了解到core-jsregenerator-runtime是做什么的


core-js

Github地址: github.com/zloirock/co…

从github上的介绍中,我们大致可以推断出,这个库它是我们所有目前babel所支持的垫片的集合体,并且我们可以知道的是,目前 @babel/polyfill, @babel/preset-env, @babel/runtime 都与这个库有着密切的关联。

那么看到这里我们其实如果想要针对polyfill继续深究,我们可能就要进去看到底stable中给我们提供了哪一些可以使用的垫片,但是人类的本质是懒惰的啊~

然后懒得的我在@babel/polyfill的官方文档中找到这样一句话 This will emulate a full ES2015+ environment (no < Stage 4 proposals) and is intended to be used in an application rather than a library/tool. 用我这抠脚的英文水品,大致看了一下,只看懂了关键的部分就是不会有小于 Stage 4 proposals的垫片实现。这里又要提到另一个知识点了,那就是我们所使用的ES的制定过程,下面会简略的介绍以下大致的一个过程以及阶段,各位大佬勿喷~

我们目前所使用的EcmaScript这一类的标准呢都是由TC39这个组织进行讨论,指定的。那么在制定的过程中呢会有这么几个阶段

  • Stage 0 - 设想(Strawman):只是一个想法,可能有 Babel插件。
  • Stage 1 - 建议(Proposal):这是值得跟进的。
  • Stage 2 - 草案(Draft):初始规范。
  • Stage 3 - 候选(Candidate):完成规范并在浏览器上初步实现。
  • Stage 4 - 完成(Finished):将添加到下一个年度版本发布中。

那么我们看到Stage4这个阶段呢基本上就是,已经确定是本年度会发布的标准了。我们在Github上找到了这个阶段的集合,具体里面有哪些内容,我就不展示出来了,大家可以点击这里自己看看学习。我们基于core-js的了解也就先到这里

regenerator-runtime

Github地址:github.com/facebook/re…

从github上查找能知道这是一个facebook提供的垫片,它主要是支持了在ES5去实现generators/yield这一块的支持~


那么这里接回来继续聊@babel/polyfill,既然它已经提供这些比较成熟的标准,我们是否可以直接使用它,来给我们提供这种转换服务呢? @babel/polyfill在webpack的使用说明 由于我们这里是在webpack的环境下面,所以我们只看到webpack这一块的说明,说了一段,大致的意思是,就是babel这边还是推荐我们在使用@babel/polyfill的时候跟@babel/preset-env一起进行使用,一起使用的过程中呢会根据useBuiltIns字段参数的不同,而需要不同的配置方式(列了三种不同的情况)。

那么如果你不跟@babel/preset-env一起使用呢,也是可以的,但是非常不建议这样操作。

叛逆的我出现了,虽然我很想知道,为什么不能这么玩,不过我们还是耐心先看完@babel/preset-env再来YY吧

@babel/preset-env

根据官方文档对于@babel/preset-env的介绍,它是基于配置的运行环境来判断代码中部分的新的规范是否需要垫片的支持。基于这一段文案,再配合刚刚@babel/polyfill这一块的就能大致的推断出,直接使用@babel/polyfill的话会把一些这个环境支持的标准语法也使用垫片来进行代替,会使整体包的体积大了很多。

在我看完@babel/preset-env相关的资料之后,我认为主要的重点会在配置这一块,我们下面会优先讲一部分,关于使用方面会在最后的 “组合拳” 当中一起加入

配置项

  • target

target这个配置项,主要就是基于你想要你的项目能在什么环境下运行的一个配置,官方给出的配置案例是下面这样的

  {
    "targets": "> 0.25%, not dead"
  }

是不是感觉相当的语义话,甚至不知道该怎么下手,哈哈哈哈。我也一样,于是我在browserslist的github上找到了这么一个全量的配置列表,我们仅需要根据这个上面,再根据我们自己的需求去进行配置就可以啦~

  • useBuiltIns

useBuiltIns这个属性与打包相关,首先他一共有三个值分别是"usage" | "entry" | false 默认是false,如果你使用的是entry,那你需要在你的文件入口处引入core-js或者是@babel/polyfill,然后它会根据你的目标环境,在入口自动把对应需要的包给打进来~ @babel-preset-env/useBuiltIns/entry @babel-preset-env/useBuiltIns/entry 以上两张图就是useBuiltIns: "entry"的情况下,在针对不同的浏览器环境下,可能会打包出来的一个结果,那么针对usage又是什么样的一个情况呢?根据官方给出的案例以及说法与entry不同的是,它是通过判断,你在开发过程中,哪些文件使用需要通过垫片支持的语法,再针对语法提供支持针对相同的一个垫片,一个文件只会引入一次 @babel-preset-env/useBuiltIns/usage @babel-preset-env/useBuiltIns/usage 这个可是相当的nice啊!最后我们再来看看false这个配置的表现,官网文档提到说,如果是false的话就不帮我们处理 import "core-js" or import "@babel/polyfill",其实我不太理解的是,它是完全不帮我做处理了,还是说只是针对我们引入的这两个垫片库不做处理,我们可以后续实验尝试一下是哪一种情况下。

  • corejs

制定对应的core-js的版本,这个知道就ok啦~

preset-env这一块,基本我们就了解到这里啦,那我们就先往下走~

@babel/core

这一块可能我这里就没有办法简单通过类似上方的这种轻快语言给大家讲清楚了,希望大家可以自己查看以下官方文档,以及搜索理解AST(抽象语法树)相关的知识,如果是指为了阅读本文的话,AST的只是并不一定要很精通,但是要有一个大概的概念就可以啦~我理解这个插件功能就是用来处理js源代码跟AST之间进行转换

babel-loader

小伙伴们肯定会说这名字一看就跟webpack有关。哈哈哈哈哈,没错!那可能有一些不太清楚小伙吧就会问,为啥一看名字就知道跟webpack有关咧?

首先webpack有四个核心的概念

  • entry
  • output
  • loader
  • plugins

entryoutput我们前面已经接触过了,大致含义就是我们打包的入口文件,跟输出文件的意思,那么loader是啥呢? webpack本身只具备了除了js的能力,那么loader就是用来将非js的文件转换成webpack可处理的js~,理解起来就像是一个编译器一样,把一些无法处理的语言语法,转换成可处理的语言语法。而plugins可能就是用来拓展更多的一些功能,比如压缩,优化,文件操作等等等等。

那么这里的babel-loader很明显就是用来处理文件中的新的标准的es语法,然后提供给webpack进行打包的啦。我们看到webpack plugins list这里对于这个插件的描述其实非常的清晰明了This package allows transpiling JavaScript files using Babel and webpack,ok~那么这句话所说,我们现在就知道要怎么在我们的脚手架中使用上babel啦~

配置babel

我们查看npm/babel-loaderbabel官网/webpack ,首先我们先来根据一致的部分进行配置,先安装一下必要的依赖

npm install -D babel-loader @babel/core @babel/preset-env webpack

接着我们在我们按照npm/babel-loader中的配置进行尝试配置webpack.config.js文件中加入如下配置信息

  // ...
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: ['@babel/preset-env']
          }
        }
      }
    ]
  }
  // ...

然后我们修改/src/main.js

import Vue from 'vue'

const text = '你好webpack4-vue'

class MyClass {
  constructor () {
    console.log('myClass')
  }
}

const isHadWebpack = text.includes('webpack')

new Vue({ 
  el: '#app',
  template: `<div>{{text}}</div>`,
  data () {
    return {
      text,
      myClass: new MyClass(),
      isHadWebpack
    }
  }
})

我们通过npm run build命令尝试一下打包, 打包成功~! 我们来看看打包出来的文件中是这样的~

var vue__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! vue */ "./node_modules/vue/dist/vue.esm.js");

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); }}

var text = '你好webpack4-vue';
var MyClass = function MyClass() {
    _classCallCheck(this, MyClass);
    console.log('myClass');
};

var isHadWebpack = text.includes('webpack');
new vue__WEBPACK_IMPORTED_MODULE_0__["default"]({
  el: '#app',
  template: "<div>{{text}}</div>",
  data: function data() {
    return {
      text: text,
      myClass: new MyClass(),
      isHadWebpack: isHadWebpack
    };
  }
});

可以看到,除了String.prototype.includes(...)之外的方法都通过垫片进行了转换,为啥只有includes没有转换,或者是垫片呢?这是因为在 @babel/polyfill 中有这么一句话 @babel/polyfill适用范围 其实也就是说,如果我们要用这种挂载在原型上的,全局作用域的方法,都必须要通过polyfill或者是我们之前提到过的core-js才可以进行支持,我们这里的话采用引入core-js赶紧试一下

首先拉取依赖npm install core-js -s然后我们修改webpack对应的env的配置

 // ...
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              [
                '@babel/preset-env',
                {
                  useBuiltIns: "usage", // 用到才引入
                  corejs: 3             // 指定版本号
                }
              ]
            ]
          }
        }
      }
    ]
  }
  // ...

根据当前配置执行命令,打包的结果如下

__webpack_require__.r(__webpack_exports__);
/* harmony import */ var core_js_modules_es_string_includes__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! core-js/modules/es.string.includes */ "./node_modules/core-js/modules/es.string.includes.js");
/* harmony import */ var core_js_modules_es_string_includes__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(core_js_modules_es_string_includes__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! vue */ "./node_modules/vue/dist/vue.esm.js");


function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }


var text = '你好webpack4-vue';

var MyClass = function MyClass() {
    _classCallCheck(this, MyClass);

  console.log('myClass');
};

var isHadWebpack = text.includes('webpack');
new vue__WEBPACK_IMPORTED_MODULE_1__["default"]({
  el: '#app',
  template: "<div>{{text}}</div>",
  data: function data() {
    return {
      text: text,
      myClass: new MyClass(),
      isHadWebpack: isHadWebpack
    };
  }
});

这回可以看到我们includes也是有了支持,只不过!还是不满意,因为这样的支持就赤裸裸的暴露在了全局,假如有一个三方库或者是一个小兄弟,自己也在全局写了一个这个,那不就覆盖掉了吗?这要怎么办呢?不要慌!针对这个问题实际上可以使用@babel/plugin-transform-runtime来解决,首先我们安装一下依赖

npm install --save-dev @babel/plugin-transform-runtime
npm install --save @babel/runtime-corejs3

然后在webpack.config.js中修改module.rules

  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /(node_modules)/,
        use: {
          loader: 'babel-loader',
          options: {
            presets: [
              [
                '@babel/preset-env',
                {
                  useBuiltIns: "usage", // 用到才引入
                  corejs: 3             // 指定版本号
                }
              ]
            ],
            plugins: [
              [
                "@babel/plugin-transform-runtime", 
                {
                  corejs: 3            // 指定版本号
                }
              ]
            ]
          }
        }
      }
    ]
  }

然后再运行打包命令后我们得到的是

/* harmony import */ var _babel_runtime_corejs3_core_js_stable_instance_includes__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! @babel/runtime-corejs3/core-js-stable/instance/includes */ "./node_modules/@babel/runtime-corejs3/core-js-stable/instance/includes.js");
/* harmony import */ var _babel_runtime_corejs3_core_js_stable_instance_includes__WEBPACK_IMPORTED_MODULE_0___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_corejs3_core_js_stable_instance_includes__WEBPACK_IMPORTED_MODULE_0__);
/* harmony import */ var _babel_runtime_corejs3_helpers_classCallCheck__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! @babel/runtime-corejs3/helpers/classCallCheck */ "./node_modules/@babel/runtime-corejs3/helpers/classCallCheck.js");
/* harmony import */ var _babel_runtime_corejs3_helpers_classCallCheck__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_babel_runtime_corejs3_helpers_classCallCheck__WEBPACK_IMPORTED_MODULE_1__);
/* harmony import */ var vue__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! vue */ "./node_modules/vue/dist/vue.esm.js");

var text = '你好webpack4-vue';

var MyClass = function MyClass() {
    _babel_runtime_corejs3_helpers_classCallCheck__WEBPACK_IMPORTED_MODULE_1___default()(this, MyClass);
  
    console.log('myClass');
};

var isHadWebpack = _babel_runtime_corejs3_core_js_stable_instance_includes__WEBPACK_IMPORTED_MODULE_0___default()(text).call(text, 'webpack');

new vue__WEBPACK_IMPORTED_MODULE_2__["default"]({
  el: '#app',
  template: "<div>{{text}}</div>",
  data: function data() {
      return {
        text: text,
        myClass: new MyClass(),
        isHadWebpack: isHadWebpack
    };
  }
});

这样之后可真的是非常的nice! 首先我们includes(...)变成了一个局部的方法~, 另外一块class的声明也抽取出来啦,这可是相当的棒棒呀~,那么到这里我们的babel基础配置就OK啦~ 我们可以来看看别的东西啦!!!

vue-loader

我们使用vue脚手架的同学都知道我们都是通过引用**.vue文件来进行组件开发,页面开发,那么我们也来写一个简单的vue文件呗~

首先我们在/src下面创建App.vue文件并写入下面的内容

<template>
  <div>{{text}}</div>
</template>

<script>
export default {
  name: 'App'
}
</script>

/src/main.js修改如下

import Vue from 'vue'
import App from './app.vue'
const text = '你好webpack4-vue'

class MyClass {
  constructor () {
    console.log('myClass')
  }
}

const isHadWebpack = text.includes('webpack')

new Vue({ 
  el: '#app',
  components: {
    App
  },
  template: '<App/>',
  data () {
    return {
      text,
      myClass: new MyClass(),
      isHadWebpack,
    }
  }
})

然后我们尝试打包一下看看~ vue-loader没添加打包报错 很明显,是因为我们没有配置相关loader的原因,那我们来看看Vue官方文档是怎么讲的 Vue官方文档-vue-loader其中讲到*.vue文件需要vue-loader或者vueify来进行构建,那我们来看看这两个工具是一个什么样的东西吧~,在查询了一波文档后了解到vueify主要是运用于Browserify的而vue-loader才是运用于webpack的那么我们来看看我们要怎么安装以及配置vue-loader吧!

根据官方指导,我们先完成最基础的依赖安装,以及配置(这里就不做重复介绍了)

vue-template-compiler 报错

我在根据官网的指令下载以后发现报错了~,查了一下,只需要同步一下vuevue-template-compiler版本同步就可以了,同步了以后基本上就可以打包成功了!!!

**注意:如果你是根据官网提示还加上了css-loader, 但是,如果你安装的css-loader的版本是4.*的那我建议你看看这个issuse **

好的,那么我们到这里就可以像是我们正常的SFC一样去编写我们的Vue组件啦~

url-loader vs file-loader

在我们实际的项目开发过程中,我们经常会引用一些资源,比如图片,gif这种,我们在看这一类资源与webpack结合的相关文章实际上我们会看到网上的文章经常会提到 url-loader 以及 file-loader 相关介绍那么我这里也不做累述

文档

总结下来就是url-loader是包含file-loader,资源超过limit参数的的情况下就是使用file-loader进行处理,没超过的情况就是转换DataURL所以在这个情况下,我们就直接使用url-loader就好了!首先我们先安装依赖npm install -D file-loader url-loader

webpack.config.js

const kb = 1024
// module.rules
  ...
  {
    test: /\.(png|jpg|jpeg|gif)$/i,
    use: [
      {
        loader: 'url-loader',
        options: {
          limit: 10 * kb,
        },
      },
    ],
  }
  ...

在创建src/assets文件夹并放进去自己喜欢的照片一张,接着在App.vue文件下修改代码

<template>
  <div class="red">
    <span>{{text}}</span>
    <img src="(你喜欢的那个图片的地址,至少要在src目录文件下)" alt="" />
  </div>
</template>

<script>
export default {
  name: 'App',
  data () {
    return {
      text: '123'
    }
  }
}
</script>

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

配置完成后 我们尝试进行打包npm run build,打包完成后,我们原本枯燥无谓的dist文件多了一个你最爱的图片~ 但是当我们打开index.html是看不到这个照片图片的,打开控制台你会发现类似的报错 file-loader esModule 报错 又是经过了一番检索,发现又是一个类似的配置css-loader 4.* 所导致的配置问题,只要给url-loader加上下列配置即可

 ...
 {
  test: /\.(png|jpg|jpeg|gif)$/i,
  use: [
    {
      loader: 'url-loader',
      options: {
        limit: 10 * kb,
        name: 'images/[name].[hash:7].[ext]',
        publicPath: './',
        esModule: false
      },
    },
  ],
}
 ...

然后把我们根目录下的html文件移到dist文件夹中,并修改html中的文件引用路径,后续都在这个基础上进行打包的验证~接着我们重新打包,打包后点开html文件我们就可以看到我们喜欢的小图片啦~ 我的图片! 那么我们既然已经遇到两次这个esModule的配置问题,事不过三我们先看看这个配置究竟是干啥的,我们来到file-loader的github看看~ file-loader的 其实看下来就是新版本的file-loader已经采用ES modules的默认引入方式,那么可能引入进来以后就是类似一个Object的形式的内容,它的一个toString的内容就是[Object Module]这样的形式,所以会变成这样,那么我们以后再次引入loader的时候就要更加的去注意这一点~

clean-webpack-plugin

我们检查一下我们的dist的文件夹中会发现一张多余的图片,为什么会这样呢?原来是因为实际上在webpack每次打包的过程中不会自动帮助我们清除对应的打包文件的文件夹(dist),这个时候就需要用到plugin的能力了因为,这个已经不是loader能解决的问题了,因为loader主要解决的就是一个其他类型(比如png|es6|TS)的文件类型需要引入处理成webpack可处理的js。而plugin本身就可以拓展很多很多的能力啦~!那么我们来看看怎么使用clean-webpack-plugin吧~

首先安装依赖

npm install --save-dev clean-webpack-plugin

webpack.config.js

// 引入插件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

// ...
plugins: [
// ...其他插件
	new CleanWebpackPlugin()
]
//...

即可,重新运行打包命令后,发现之前冗余的一些文件都被删除了,只剩下了我们的目标打包内容,但是!这样又会有另一个问题的出现,那就是我们之前放进去dist文件html文件也被清掉了,这个是我们不愿意看到的,那么我们看看怎么解决这个问题!

html-webpack-plugin

首先基于官方文档我们了解到,这个插件主要提供的是一个在webpack的bundles中快速创建html的这么一个插件,那么这个插件的自由度,还是比较高的,我们可以看到配置项中还是提供了很多的选项可以使用,包括一系列相关的钩子给其他插件等~

首先我们先安装依赖

npm i --save-dev html-webpack-plugin

然后在我们配置项webpack.config.js中做如下配置

const HtmlWebpackPlugin = require('html-webpack-plugin')
// ...
plugins: [
  new HtmlWebpackPlugin({
    filename: 'index.html',
    template:  path.resolve(__dirname, './index.html')
  })
]
// ... 

然后修改根目录下的html为

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
  </head>
  <body>
    <div id="app"></div>
  </body>
</html>

然后运行打包命令npm run build,打包成功!! 当然html-webpack-plugin还有很多其他的能力,但是我们就不一一在这里展开了,感兴趣的朋友可以自己去看看对应的github!!

extract-text-webpack-plugin

细心的小伙伴一定会发现,在我们现有的css(作者这里采用的scss),并没有单独的抽离出来,如果不知道css-loader相关的配置是从哪边来的呢,可以往回翻一下看到vue-loader那块。那么我们为了要让我们的css能够独立出来,在这里我们使用的了extract-text-webpack-plugin下面我们一起看看应该如何配置吧!

首先我们先安装依赖

npm install --save-dev extract-text-webpack-plugin

安装完成后我们在webpack.config.js增加并修改如下内容

const ExtractTextPlugin = require("extract-text-webpack-plugin");
// module.rules 
  {
    test: /\.scss$/,
    use: ExtractTextPlugin.extract({
      fallback: 'vue-style-loader',
      use: [
        {
          loader: 'css-loader',
          options: {
            esModule: false
          }
        },
        'sass-loader'
      ]
    })
  }
// plugins
  ...
      new ExtractTextPlugin('styles.css')
  ...

运行打包命令之后就报错了! ExtractTextPlugin打包报错 上网一顿检索之后,发现主要是当前主流版本的extract-text-webpack-plugin并不支持webpack4,怎么解决呢?尝试安装下方依赖

npm install --save-dev extract-text-webpack-plugin@next

重新进行打包,打包成功!这个时候我们看到我们打包生成的文件夹中已经如下

抽离css后的文件接口

uglifyjs-webpack-plugin

打开我们的main文件,我们会发现JS并没有进行全量压缩,并且还是有注解的一个状态,那么我们想要压缩代码,就必须要引入插件uglifyjs-webpack-plugin,当然我们也可以修改我们的mode:'production'他也会启用一些内置的插件如下 mode说明 那么其中也包括了uglifyjs-webpack-plugin,那么我们目前的需求也是能够达到的,如果有更多定制化的需求我们还是需要,自行拉取依赖后,根据配置项进行配置

webpack-bundle-analyzer

最后打包基础的内容都已经配置的7788了,优化的内容我们将会放到后面的优化篇去进行讲解,我们来配置一下打包体积分析工具吧webpack-bundle-analyzer

首先我们先安装依赖https://github.com/webpack-contrib/webpack-bundle-analyzer 然后在代码中引入如下内容

const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// plugins
[
	...
	new BundleAnalyzerPlugin()
	...
]

运行命令!npm run build webpack-bundle-analyzer

总结

到这里我们的webpack-vue脚手架之build篇就到一段落了,这里完成后一个最基础最基础的vue脚手架(build)就完成了,如果想要配置更加细致,或者更加优秀的脚手架,请不要错过后面的其他相关文章哦,站内的大哥大姐们有什么问题,请直接BB我,我们互相学习!!