# 为什么需要模块化

回顾下 JavaScript 原始功能

在网页开发的早期, js 制作作为一种脚本语言,做一些简单的表单验证或动画实现等,<mark>那个时候代码还是很少的</mark>。

那个时候的代码是怎么写的呢?直接将代码写在 <script> 标签中即可

随着 ajax 异步请求的出现,<mark>慢慢形成了前后端的分离</mark>
客户端需要完成的事情越来越多,<mark>代码量也是与日俱增</mark>。
为了应对代码量的剧增,我们通常会将代码组织在多个 js 文件中,进行维护。
但是这种维护方式,依然不能避免一些灾难性的问题。

比如全局变量同名问题:(下图)

另外,这种代码的编写方式对 js 文件的依赖顺序几乎是强制性的
但是当 js 文件过多,比如有几十个的时候,弄清楚它们的顺序是一件比较同时的事情。
而且即使你弄清楚顺序了,也不能避免上面出现的这种尴尬问题的发生。

# 模块化?组件化?

个人理解:<mark> A P P APP\subset组件\subset模块 APP</mark>

  • <mark>一个 APP 有多个组件</mark>(如:头部搜索栏、中间数据展示框、底层的选项框)

  • <mark>一个组件有多个模块</mark>(如:搜索栏有输入模块、搜索模块、缓存模块等。。。)
    【两个组件之间的模块没关系,可以重复,可以不重复】

# 匿名函数的解决方案

以前,我们可以使用<mark>匿名函数来解决方面的重名问题</mark>
在aaa.js文件中,我们使用匿名函数

但,这会导致代码不可复用。

# 使用模块作为出口

作为成年人,<mark>变量重名的解决、代码复用</mark> 我全都要!!

name,就把闭包 return 出一个 变量导出

接下来,我们在main.js中怎么使用呢?
我们只需要使用属于自己模块的属性和方法即可

这就是模块最基础的封装,事实上模块的封装还有很多高级的话题:
但是我们这里就是要认识一下为什么需要模块,以及模块的原始雏形。
幸运的是,前端模块化开发已经有了很多既有的规范,以及对应的实现方案。

常见的模块化规范:
CommonJS、AMD、CMD,也有ES6的Modules

# CommonJS(了解)

模块化有两个核心:导出和导入
CommonJS 的导出:

CommonJS 的导入

# ES6的export和import

+《JS - 13 - 模块化》 - https://blog.csdn.net/LawssssCat/article/details/104463632

## export基本使用

export指令用于导出变量,比如下面的代码:

上面的代码还有另外一种写法:

## 导出函数或类

上面我们主要是输出变量,也可以输出函数或者输出类

上面的代码也可以写成这种形式:

## export default

某些情况下,一个模块中包含某个的功能,我们并不希望给这个功能命名,而且让导入者可以自己来命名
这个时候就可以使用export default

我们来到main.js中,这样使用就可以了
这里的myFunc是我自己命名的,你可以根据需要命名它对应的名字

另外,需要注意:
export default在同一个模块中,不允许同时存在多个。

## import使用

我们使用export指令导出了模块对外提供的接口,下面我们就可以通过import命令来加载对应的这个模块了
首先,我们需要在HTML代码中引入两个js文件,并且类型需要设置为module

import指令用于导入模块中的内容,比如main.js的代码

如果我们希望某个模块中所有的信息都导入,一个个导入显然有些麻烦:
通过可以导入模块中所有的export变量
但是通常情况下我们需要给起一个别名,方便后续的使用

# 什么是Webpack?

<mark>前端、模块化、打包、工具</mark>

我们先看看官方的解释:

At its core, webpack is a static module bundler for modern JavaScript applications.

从本质上来讲,webpack是一个现代的<mark>JavaScript应用的静态模块打包工具</mark>。

我们从两个点来解释上面这句话:模块 和 打包

## 模块

模块概念前面说了。
就是 <mark>过程闭包、结果导出、使用导入</mark>

<mark>但是这样,又有一个问题,模块和模块之间相互依赖,需要管理工具。管理的手段就是“打包”</mark>

## 打包

就是将 webpack中各种模块进行合成一个包(Bundle)

<mark>在打包过程中,会对资源进行加工。
如:压缩图片、将scss转成css、将es6语法转成es5语法、将typeScript转成javaScript等</mark>

# 和 grunt/gulp 的对比

grunt/gulp 也是一个类似的工具。但是没有webpack强大。

下面左下对比

  • 模块依赖简单、只需要进行简单的合并、压缩 ,那么,你可以使用 grunt/gulp
  • 但是要对模块进行管理(模块之间依赖非常复杂了),那么需要用 webpack

  • <mark>grunt/gulp 强调的是 前端流程的自动化,模块化不是核心</mark>
  • <mark>webpack 强调模块化开发管理,前端自动(如文件压缩合并、预处理等)只是他的附带功能</mark>

# webpack 全局安装

官方教程:https://www.webpackjs.com/guides/installation/

安装webpack首先需要安装Node.js,Node.js自带了软件包管理工具npm
查看自己的node版本: (要大于9)

node -v 

全局安装webpack(这里我先指定版本号3.6.0,因为vue cli2依赖该版本)
<mark>官方不推荐全局安装,我们学习,怎么方便怎么来</mark>

npm install webpack@3.6.0 -g

<mark>这里,版本太高会依赖其他东西,你不会调的话,会报错哦</mark>

# 创建工程目录

准备工作

我们创建如下文件和文件夹:

文件和文件夹解析:

  • dist 文件夹(distribution):用于存放之后<mark>打包的文件</mark>
  • src 文件夹:用于存放我们写的<mark>源文件</mark>
    • main.js :项目的<mark>入口文件</mark>。具体内容查看下面详情。
    • mathUtils.js:定义了一些数学<mark>工具函数</mark>,可以在其他地方引用,并且使用。具体内容查看下面的详情。
  • index.html:浏览器打开展示的首页html
  • package.json:通过npm init生成的,npm包管理的文件(<mark>暂时没有用上,后面才会用上</mark>)

mathUtils.js 文件中的代码:

function add(num1, num2) {
  return num1 + num2;
}

function mul(num1, num2) {
  return num1 * num2;
}

module.exports = {
  add,
  mul
}

main.js 文件中的代码:

const {
  add,
  mul
} = require('./mathUtils.js');

console.log(add(20, 30))
console.log(mul(20, 30))

# js文件的打包

<mark>不可以直接使用我们前面写好的js</mark>
<mark>因为如果直接在index.html引入这两个js文件,浏览器并不识别其中的模块化代码。</mark>
<mark>且后期非常不方便对它们进行管理。</mark>

所以,我们需要用到webpack工具,对多个js文件进行打包。


来到 工程根目录,控制台输入命令

 webpack .\src\main.js .\dist\bundle.js

工程目录 ./dist 下就 多了个打包好的文件

# 使用打包后的文件

打包后会在dist文件下,生成一个bundle.js文件

文件内容有些复杂,这里暂时先不看,后续再进行分析。

bundle.js文件,是webpack处理了项目直接文件依赖后生成的一个js文件,
<mark>我们只需要将这个js文件在index.html中引入即可</mark>


# webpack配置

我们希望通过配置,简化操作

## npm init -y

写webpack配置通常要用到 node 的环境

因此,下面生成 node 配置

npm init -y 


## 入口和出口

官方教程:https://www.webpackjs.com/guides/getting-started/#使用一个配置文件

指定默认的 源码目录(.\src\main.js),输出目录(.\dist\bundle.js

首先,创建一个 webpack.config.js 文件

const path = require('path')

module.exports = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  }
}

以后打包,只需要输入

webpack

就行了

## package.json中定义 script

但是,每次执行都敲这么一长串有没有觉得不方便呢?
OK,我们可以在package.json的scripts中定义自己的执行脚本。

## 局部安装webpack

目前,我们使用的webpack是全局的webpack,如果我们想使用局部来打包呢?

因为一个项目往往依赖特定的webpack版本,<mark>全局的版本可能很这个项目的webpack版本不一致,导出打包出现问题</mark>。
<mark>所以通常一个项目,都有自己局部的webpack</mark>。

第一步,项目中需要安装自己局部的webpack
这里我们让局部安装webpack3.6.0

npm install webpack@3.6.0 --save-dev

–save-dev 是开发时依赖,项目打包后不需要继续使用的。

Vue CLI3 中已经升级到 webpack4 ,但是它(webpack4)将配置文件隐藏了起来,所以查看起来不是很方便。


看 package.json , 里面会多个 devDependencies 就是指定 开始时依赖的

再看目录,多了个 node_modules 目录,里面一堆依赖

前面两部的必要性

<mark>局部安装webpack 和 添加 build 指令。能让打包时候,webpack 从本地依赖当中优先打包(而不是从全局)</mark>

# webpack核心:loader

loader是webpack中一个非常核心的概念

<mark>需求:我们写好的东西,需要对其进行转换</mark>,转换成低版本浏览器也能使用的文件格式。(提高代码通用性)
如:我们需要加载css、图片,也包括一些高级的将 ES6 转换成 ES5 代码,将 TypeScript 转换成 ES5 代码,加你 scss、less 转成 css,将 .jsx.vue文件转成 js 文件等等。

<mark>但是,webpack本身不支持此类的转换</mark>,需要我们给 webpack扩展loader

步骤

  • 通过 npm 安装使用的 loader
  • 在 webpack.config.js 中的 modules 关键下进行配置

大部分 loader 我们都可以在 webpack 的官方网站中找到 - 官网 loaders

## 案例:添加 css 样式的依赖

随便写一个样式

body{
  background-color: red ;
}

去到官网 找 loaders

、、

看文字,可以领悟到,我们要同时使用 style-loader 和 css-loader

他的代码也这样写了

然后按照上面写的 ,先安装 loader

npm install style-loader --save-dev
npm install --save-dev css-loader

在入口文件引入 依赖

webpack.config.js 添加配置

,
  module: {
    rules: [{
      test: /\.css$/,
      // css-loader 只负责将css加载,不负责生效
      // 如果要生效,还要安装 style-loader负责将样式添加到 DOM 中
      // 使用多个 loader 时候,是从右向左
      use: [{
          loader: "style-loader"
        },
        {
          loader: "css-loader"
        }
      ]
    }]
  }

编译 (之前配置了,所以可以这样写,如果不行,看上章配置)

npm run build

done

# less文件处理

随便写个 less 文件

@fontSize: 50px;
@fontColor: orange;

body {
  font-size: @fontSize;
  color: @fontColor;
}

main.js 中添加 依赖

// 依赖less文件
require('./css/special.less');
document.writeln(`<h2>你好啊!</h2>`)

查官网资料:https://www.webpackjs.com/loaders/less-loader/

知道安装 :

npm install --save-dev less-loader less

并且在 webpack.config.js中添加 rules

// webpack.config.js
module.exports = {
    ...
    module: {
        rules: [{
            test: /\.less$/,
            use: [{
                loader: "style-loader" // creates style nodes from JS strings
            }, {
                loader: "css-loader" // translates CSS into CommonJS
            }, {
                loader: "less-loader" // compiles Less to CSS
            }]
        }]
    }
};

编译 (之前配置了,所以可以这样写,如果不行,看上章配置)

npm run build

done

# 图片处理

修改 css样式,引用图片资源

body {
  /* background-color: red ; */
  background: url('../img/spring.jpg');
}

编译时候,会报错


添加 rules
<mark>注意:这里要改limit,大于你请求的图片大小, 如:10kb就写10240以上</mark>

{
        test: /\.(png|jpg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              limit: 8192
            }
          }
        ]
      }

再次编译

done

# 图片处理 - limit 分析

当加载图片,小于 limit 时,会将图片编译成 base64字符串形式

而当 大于 limit 时,会用 file-loader 处理。(你可以试下:换张大图,再次编译,会出现以下错误)

原因是你没有安装file loader(那安装呗)

安装编译后,<mark>发现仍然没有显示</mark>
并且控制台报错

控制台说的 是图片找不到

看body上的 url 引用,引用的是 index.html 即 src目录下的 图片。

而我们图片生成在了 /dist 目录下,我们把图片拷贝到根目录,

图片找到了,

但每次手动更改显然不可行,怎么办?

只需要在 webpack 配置里面 的 output 里面 加一个属性

看官方文档

# 图片处理 - 输出名字

图片找到了,但是,如果一堆乱七八糟名字的图片放在 dist目录下,也很头疼

这是需要在 options 里面再添加一个属性 name

(如下)

name: 'img/[name].[hash:8].[ext]' 

name 图片原来的名字
hash 根据图片信息算出来了hash值(冲突概率极小)
hash:8 截取hash值前8位
ext 图片原有后缀

结果

# 图片处理 - 总结

  • 当加载的图片,小于limit时,会将图片编译成base64字符串形式
  • 当加载的图片,大于limit时,需要使用file-loader模块进行加载(这时候需要配置 output.publicPath)
{
  test: /\.(png|jpg|gif)$/,
   use: [
     {
       loader: 'url-loader',
       options: {
         limit: 8192
       }
     }
   ]
 }
module.exports = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
    publicPath: 'dist/',
  },

同时, 如果想定制图片转换后的目录和名字,需要这样配置(下图) - 官方的相关文档

      }]
    }, {
      test: /\.(png|jpg|gif|jpeg)$/,
      use: [{
        loader: 'url-loader',
        options: {
          // 当加载的图片,小于limit时,会将图片编译成base64字符串形式
          // 当加载的图片,大于limit时,需要使用file-loader模块进行加载(这时候需要配置 output.publicPath)
          limit: 8192,
          name: 'img/[name].[hash:8].[ext]' 
        }
      }]
    }]
  }

# ES6语法处理

如果你仔细阅读webpack打包的js文件,<mark>发现写的ES6语法并没有转成ES5</mark>,那么就意味着可能一些对ES6还不支持的浏览器没有办法很好的运行我们的代码。

webpack 脚手架 实现 ES6转ES5

这里不用脚手架

看官网怎么做

下面,就用 babel 为例子,实现转换。

npm install --save-dev babel-loader@7 babel-core babel-preset-es2015

# 引入 vue.js

后续项目中,我们会使用Vuejs进行开发,而且会以特殊的文件来组织vue的组件。
所以,<mark>下面我们来学习一下如何在我们的webpack环境中集成Vuejs</mark>
现在,我们希望在项目中使用Vuejs,那么必然需要对其有依赖,所以需要先进行安装

npm install --save vue 

注:<mark>因为我们后续是在实际项目中也会使用vue的,所以并不是开发时依赖</mark> ,而是用 --save

那么,接下来就可以按照我们之前学习的方式来使用 Vue

main中添加

// 引入 vue 模块
import Vue from 'vue' ;

const app = new Vue({
  el: '#app' ,
  data: {
    message: '你好啊!'
  }
})

index 中添加


<body>

  <div id='app'>
    <h2>{{message}}</h2>
  </div>
  <script src="./dist/bundle.js"></script>
</body>

# 打包 vue 项目 – 错误信息

修改完成后,重新打包,运行程序:
打包过程没有任何错误(因为只是多打包了一个vue的js文件而已)
但是运行程序,没有出现想要的效果,而且浏览器中有报错

 You are using the runtime-only build of Vue where the template compiler is not available. 
 Either pre-compile the templates into render functions, or use the compiler-included build.

你正在用 Vue 的 runtime-only 版本编译,这个版本对 template 是不可用的。
你要么把 template 放进预编译函数,要么使用 complier-included 版本编译。

这个错误说的是我们使用的是runtime-only版本的Vue,什么意思呢?

这里我只说解决方案:Vue不同版本构建,后续我具体讲解runtime-only和runtime-compiler的区别。

vue 官方给出的 解决方案 《运行时 + 编译器 vs. 只包含运行时》

所以我们修改webpack的配置,添加如下内容即可

module.exports = {

	.......

  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js' // 用 webpack 1 时需用 'vue/dist/vue.common.js'
    }
  }
}

# SPA 概念

我们现在 主要开发
SPAsimple page web application) 单页面 Web 应用 - 详细介绍

那如果后期有多个页面怎么办?
.
我们会用到路由技术
.
vue-router (前端路由)(后期讲到,现在不管)

# el和template区别

正常运行之后,我们来考虑另外一个问题:

  • 如果我们希望将 data 中的数据显示在界面中,就必须是修改index.html
  • 如果我们后面自定义了组件,也必须修改index.html来使用组件
  • 但是 html <mark>模板在之后的开发中,我并不希望手动的来频繁修改</mark>,是否可以做到呢?

# 编写 .vue 文件

定义 template 属性:

  • 在前面的 Vue 实例中,我们定义了 el 属性,用于和 index.html 中的 #app 进行绑定,让 Vue 实例之后可以管理它其中的内容

  • 这里,我们可以将 div元素 中的 {{message}} 内容删掉,只保留一个基本的 iddiv 的元素

  • 但是如果我依然希望在其中显示 {{message}} 的内容,应该怎么处理呢?

  • 我们可以写一个 .vue 文档,并且把组件的代码放在其里面,代码如下:

    App.vue

    <template>
      <div>
        <h2 class="title">{{ message }}</h2>
        <button @click="btnClick">按钮</button>
        <h2>{{ name }}</h2>
      </div>
    </template>
    
    <script> export default { name: "App", // 组件的标签名字(在 vue dev-tool 中可以看到) data() { return { message: "** 你老*!", name: "梁非凡!!!" }; }, methods: { btnClick() { alert("btnClick"); } } }; </script>
    
    <style> .title { color: green; } </style>
    
    

    main.js

    	// 引入 vue 模块
    import Vue from 'vue';
    
    import App from './vue/App.vue'
    
    new Vue({
      el: '#app',
      template: `<App/>`,
      components: {
        App
      }
    })
    

# vue-loader

上面代码写好后,我们编译报错(下图),原因很简单,没有 .vue 后缀的 loader 。(那就安装呗)


查看文档 - Vue Loader

运行下面指令安装

npm install -D vue-loader vue-template-compiler

–save-dev=-D,安装的包将写入packege.json里面的devDependencies,devdependencies:只有开发环境下需要依赖的库

配置里面添加

// webpack.config.js
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  module: {
    rules: [
      // ... 其它规则
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      }
    ]
  },
  plugins: [
    // 请确保引入这个插件!
    new VueLoaderPlugin()
  ]
}

<mark>以上弄好,编译</mark>


这里如果编译出现异常
VueLoaderPlugin is not defined
参考这篇文档
vue-loader@15.x VueLoaderPlugin 踩坑

// 打开webpack的配置文件 webpack.config.js:
const { VueLoaderPlugin } = require('vue-loader');

done!

# plugin的使用

webpack 中的插件,就是对 webpack <mark>现有功能的各种扩展</mark>,比如打包优化,文件压缩等等。

loader和plugin区别

  • loader主要用于转换某些类型的模块,它是一个 <mark>转换器</mark>。
  • plugin是插件,它是对webpack本身的扩展,是一个 <mark>扩展器</mark>。

plugin的使用过程:

  • 步骤一:通过 npm 安装需要使用的p lugins (某些webpack已经内置的插件不需要安装)
  • 步骤二:在 webpack.config.js 中的 plugins 中配置插件。

下面,我们就来看看可以通过哪些插件对现有的webpack打包过程进行扩容,让我们的webpack变得更加好用。

## 添加版权的 Plugin

我们先来使用一个最简单的插件,<mark>为打包的文件添加版权声明</mark> (如下)


(了解:MIT是一个比较开放的协议)

该插件名字叫 BannerPlugin ,属于 webpack 自带的插件。 - – - - 官方介绍

按照下面的方式来修改 webpack.config.js 的文件:

const webpack = require('webpack');


....


  plugins: [
    new webpack.BannerPlugin({
      banner: "hash:[hash], chunkhash:[chunkhash], name:[name], filebase:[filebase], query:[query], file:[file]"
    })
  ]

重新打包程序:查看 bundle.js 文件的头部,看到如下信息

## 打包html的plugin

目前,我们的 index.html 文件是存放在项目的根目录下的。
但在真实发布项目时,发布的是 dist 文件夹中的内容,我们应该吧 index.html 也放在 dist 里面(同时保证依赖不乱)

<mark>HtmlWebpackPlugin 插件可以为我们做这些事情:</mark>

  • 自动生成一个index.html文件(可以指定模板来生成)
  • 将打包的js文件,自动通过script标签插入到body中

安装 HtmlWebpackPlugin 插件: api

npm install --save-dev html-webpack-plugin
var HtmlWebpackPlugin = require('html-webpack-plugin');
var path = require('path');

var webpackConfig = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, './dist'),
    filename: 'bundle.js' , 
    // publicPath: 'dist/', 这个注释掉 // 以后可以作为项目路径
  },
  plugins: [new HtmlWebpackPlugin({
      template: 'index.html' // 指定模板
    })
  ]
};

关于 这个插件的其他配置 参考 - 官方文档

done!

## js 压缩插件

API - https://www.webpackjs.com/plugins/uglifyjs-webpack-plugin/

npm i -D uglifyjs-webpack-plugin

错误:Cannot read property 'compilation' of undefined
把版本改低,然后 npm install

done

# 搭建本地服务器

webpack 提供了一个可选的本地开发服务器,这个本地服务器基于 node.js 搭建,内部使用 express 框架,可以实现我们想要的让浏览器自动刷新显示我们修改后的结果。

不过它是一个单独的模块,在 webpack 中使用之前需要先安装它 - 官方API文档

npm install --save-dev webpack-dev-server

修改 webpack.config.js

devServer: {
   contentBase: './dist', 
   inline: true
},

其中:
还可以设置其他选项
contentBase :为哪个文件夹提供本地服务,默认是根文件夹,我们这里需要填写 ./dist
port :端口号
inline : 页面实时刷新
historyApiFallback : 在 SPA 页面中,依赖HTML5的history模式(<mark>后面路由时候讲</mark>)

让我们添加一个 script 脚本,可以直接运行开发服务器(dev server):

package.json

"start": "webpack-dev-server --open",
  • --open 自动打开

现在,我们可以在命令行中运行 npm start or npm run start,就会看到浏览器自动加载页面。如果现在修改和保存任意源文件,web 服务器就会自动重新加载编译后的代码。试一下!
关于 Server 的更多

如果报错:Error: Cannot find module 'webpack-cli/bin/config-yargs'
那是我们没有安装脚手架
然后你的版本太高了
我们把版本降到 2.9.3(webpac3.6.0)

done


除此之外,vscode的插件 LiveServer 也可以实现这功能,一键安装不用配置,适合新手玩。try it~

# 配置文件分离

配置很多,有的生产环境不需要,有的开发环境不需要

我们需要把配置文件分离(为脚手架打基础)

创建新文件夹 build 分成三个文件 , 把 webpack.config.js 的所有配置进行拆分

  • base 公共
  • dev 开发
  • prod 生产

base.config.js(下)

const path = require('path')
const {
  VueLoaderPlugin
} = require('vue-loader');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
  entry: './src/main.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js',
    // publicPath: 'dist/', // 后面可以作为项目路径
  },
  module: {
    rules: [{
      test: /\.css$/,
      // css-loader 只负责将css加载,不负责生效
      // 如果要生效,还要安装 style-loader负责将样式添加到 DOM 中
      // 使用多个 loader 时候,是从右向左
      use: [{
          loader: "style-loader"
        },
        {
          loader: "css-loader"
        }
      ]
    }, {
      test: /\.less$/,
      use: [{
        loader: "style-loader" // creates style nodes from JS strings
      }, {
        loader: "css-loader" // translates CSS into CommonJS
      }, {
        loader: "less-loader" // compiles Less to CSS
      }]
    }, {
      test: /\.(png|jpg|gif|jpeg)$/,
      use: [{
        loader: 'url-loader',
        options: {
          // 当加载的图片,小于limit时,会将图片编译成base64字符串形式
          // 当加载的图片,大于limit时,需要使用file-loader模块进行加载(这时候需要配置 output.publicPath)
          limit: 8192,
          name: 'img/[name].[hash:8].[ext]'
        }
      }]
    }, {
      test: /\.js$/,
      // 排除 node_modules 里面的 js
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
        options: {
          // presets: ['@babel/preset-env']
          presets: ['es2015']
        }
      }
    }, {
      test: /\.vue$/,
      loader: 'vue-loader'
    }]
  },
  resolve: {
    alias: {
      'vue$': 'vue/dist/vue.esm.js' // 用 webpack 1 时需用 'vue/dist/vue.common.js'
    }
  },
  plugins: [
    // 请确保引入这个插件!
    new VueLoaderPlugin(),
    new webpack.BannerPlugin({
      banner: "hash:[hash], chunkhash:[chunkhash], name:[name], filebase:[filebase], query:[query], file:[file]"
    }),
    new HtmlWebpackPlugin({
      template: 'index.html'
    }),
  ]
}

prod.config.js(下:生产环境)

const UglifyWebpackPlugin = require('uglifyjs-webpack-plugin');
const webpackMerge = require('webpack-merge'); // 新添加的,用于合并
const baseConfig = require('./base.config')  // 新添加的,用于合并

module.exports = webpackMerge(baseConfig, {
  plugins: [
    // 开发阶段不需要丑化
    new UglifyWebpackPlugin()
  ]
})

dev.config.js(下:开发环境)

const webpackMerge = require('webpack-merge');// 新添加的,用于合并
const baseConfig = require('./base.config')// 新添加的,用于合并

module.exports = webpackMerge(baseConfig, {
  devServer: {
    contentBase: './dist',
    inline: true
  }
})

# 配置文件合并(分离后)

安装

npm i -D webpack-merge

修改 package.json,指定新配置的位置

    "build": "webpack --config ./build/prod.config.js",
    "start": "webpack-dev-server --open --config ./build/dev.config"
  • build 用于发布
  • start 用于开发

最后修改 base.config.js 里面 output 指定的输出地址

最后 build 和 start 看效果吧

done