看完你就会用 webpack 了

·  阅读 2032

终极目标

可以使用 webpack 打包 vue 项目。

总体计划

  1. webpack 安装和简单使用
  2. 通过配置文件增加打包的功能
  3. 学习各种loader可以让webpack去打包各种文件
  4. 学习 plugins强大webpack 的功能
  5. 学会配置 webpack-dev-server 可以在开发过程中实时更新预览代码
  6. 配置webpack 实现 .vue 文件的打包

webpack-安装基本使用

学习目标

  • 明白 webpack 的作用。
  • 掌握 webpack 的基本使用。
  • 解决项目中代码打包的问题。(通过 webpack 对代码进行打包)

学习计划

  1. webpack的用处。
  2. webpack 的安装环境
  3. webpack 的安装
  4. 代码文件结构
  5. 如何改造普通代码文件为模块化,便于 webpack 打包
  6. 使用 简单命令预览 webpack 打包效果
  7. 查看打包后的 js 并简单介绍下 webpack 打包依据。
  8. 通过 es6 模块化文件使用 webpack 打包
  9. 总结

开始学习

webpack 的世界 一切皆模块

1. webpack 的作用(打包)

webpack 把模块收集梳理打包

  • 对我们开发的项目进行打包(编译,把我们的代码转换成浏览器可以编译的代码,例如 es6 转 es5,scss 转 css ,css 增加前缀,把.vue 拆分成.js和.css)
    • 开发过程中时时编译
      • 通过 webpack server 生成一个临时的本地服务,对我们开发的项目的代码进行时时编译。
    • 项目开发完毕对资源进行打包
      • 压缩
      • 不压缩

2. 安装 webpack

webpack中文网

1. 安装环境

  1. 安装 node,目前安装 node 会自动安装 npm。

    node 中文网

  2. 创建一个文件夹。例如 demo1

  3. 使用 npm 命令初始化 node 环境。

    npm init -y
    复制代码

    这样会产生一个 package.json 文件

    {
      "name": "demo1",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1"
      },
      "keywords": [],
      "author": "",
      "license": "ISC"
    }
    
    复制代码

2. 安装webpack

1.在命令行工具中输入(推荐局部安装)

npm i webpack webpack-cli -D
复制代码

当看到命令行中出现如下代码,代表安装成功了。

+ webpack-cli@3.3.12
+ webpack@4.43.0
added 391 packages from 218 contributors in 56.033s
复制代码
 "devDependencies": {
    "webpack": "^4.43.0",
    "webpack-cli": "^3.3.12"
  }
复制代码

i 是 install 的简写

-D 是--save-dev的简写,其包名称及版本号会存在 package.json 的 devDependencies 这个里面,而--save则会将包名称及版本号放在 dependencies 里面。

延伸:dependencies是运行时依赖,devDependencies是开发时的依赖 (这里大家知道就可以了,以后的课程会终点介绍)

webpack 4x以上,webpack将命令相关的内容都放到了webpack-cli,所以还需要安装webpack-cli。

注意:

  1. webpack 和 webpack-cli 推荐同时安装,这样可以保证webpack-cli 对应 当前安装的 webpack。

  2. 项目名称不要叫 webpack 会导致安装失败。

  3. 如何查看版本号?由于webpack 不是全局安装 查看版本不能使用

    webpack -v
    复制代码

    而是使用

    node_modules\.bin\webpack -v
    // 4.43.0
    复制代码

    或者

    npx webpack -v
    // 4.43.0
    复制代码

者来检测版本,注意这里npm版本号要求 5.2 之后。

npx webpack 等价于 node_modules\.bin\webpack

3. 创建基本文件代码

环境准备完成之后我们开始创建几个基本文件,其目录结构如下:

deomo1/root
|-index.html
|-index.js
|-package.json
|-tool.js
复制代码

index.html 代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app"></div>
</body>
<script src="tool.js"></script>
<script src="./index.js"></script>
</html>
复制代码

tool.js 代码

const updateDom = (id, content) =>{
    window.document.getElementById(id).innerHTML =  content
}
复制代码

index.js 代码

updateDom('app','传智播客')
复制代码
痛点
  1. index.js 依赖 tool.js 所以 index.html 中文件不可以换位置

  2. 多人开发项目时候无法保证变量是否唯一性(变量冲突)。例如两个文件中分别存在 tool.js var a = 100;index.js var a =1000;

  3. 低版本浏览器不识别 ES6 语法。

  4. 代码没有经过混淆存在安全隐患,例如别人可以通过你的代码推断出服务器接口请求的一些参数。

  5. 随着 js 文件个数增加,增加了项目管理的难度,例如各个js 文件依赖,变量等等

解决方案

​ 通过使用 webpback 把多个 js 文件打包成一个。

4. 修改基本文件代码为模块化写法

本代码实例为 CommonJS 模块化写法,具体改造如下

tool.js

const updateDom = (id, content) =>{
    window.document.getElementById(id).innerHTML =  content
}
// nodejs中的模块
module.exports = {
    updateDom
}
复制代码

index.js

const {updateDom} = require('./tool');
updateDom('app','传智播客')
复制代码

改完之后的代码我们再次直接通过浏览器打开发现浏览器报错,因为浏览器不能识别。接下来通过 webpack 对我们的diamond进行打包操作。

注意

在 webpack 4 中,可以无须任何配置就可以使用。

  1. 简单的打包操作

    npx webpack index.js //入口文件
    复制代码

    npx 解释见上文

    结果

    Hash: c4b4044439973defe187
    Version: webpack 4.43.0
    Time: 425ms
    Built at: 2020-07-16 4:51:35 PM
      Asset      Size  Chunks             Chunk Names
    main.js  1.05 KiB       0  [emitted]  main
    Entrypoint main = main.js
    [0] ./index.js 71 bytes {0} [built]
    [1] ./tool.js 160 bytes {0} [built]
    复制代码

    同时根目录生成了一个叫做 dist 的文件夹里面存在一个 main.js 的文件。

    同时有一段黄色的警告,因为我们没有告诉 webpack 我们的需要打包的模式是开发模式(我理解为开发代码阶段)还是生产模式(我一般理解为打包上线)。

5 打包后的 js

main.js 就是 index.jstool.js 两个文件打包后的结果。

基本原理 webpack 会分析入口文件中的引用关系把相关的文件合并到一起,例如:

如果 index.js 中没有引用 tool.js 那么打包的 main.js 就没有tool.js 的代码。

(简单给学生看下mian.js)

6. 引入打包后的js

修改 index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <div id="app"></div>
</body>
    <script src="./dist/main.js"></script>
</html>

复制代码

7. 使用 ES6 的模块化导出

创建一个 tooles6.js 文件

const log = (content) => {
    console.log(Date.now(), content)
}

// es6 模块化导出
export { log }

复制代码

在 index.js 文件中引入

// node 模块化导入
const {updateDom} = require('./tool');

 // es6 模块化导入
import {log} from './tooles6';

updateDom('app','传智播客')

log('测试webpack是否能识别es6的模块化')

复制代码

小结

  1. webpack 自动识别各种依赖处理打包文件
  2. webpack 通过入口文件
  3. webpack 可以用来打包多个或一个 js 文件(多个合成一个)
    1. 优点:不必去关心它们的依赖
  4. 基于 node.js 不建议全局安装,直接通过 -D 安装到项目即可。
  5. 每次打包都会生成新的文件,如果有同样名字的会覆盖
  6. 支持两种模块化
    1. commonjs
    2. es6

webpack-基本配置

学习目标

我们如何配置webpack 来满足我们的需求?

我们如何简化 webpack 的命令,可以快速使用

我们如何自定义打包入口和出口路径?

通过下面的课程我们可以掌握webpack 的基本配置满足我们项目打包的基本需求。

学习计划

  1. 创建默认配置文件 webpack.config.js
  2. 指定配置文件进行打包操作
  3. 通过package.json 进行简化 webpack 的命令
  4. 自定义打包文件和输出文件位置及名称
  5. 总结

开始学习

在 webpack 4 中,可以无须任何配置使用,然而大多数项目会需要很复杂的设置,这就是为什么 webpack 仍然要支持 配置文件。这比在终端(terminal)中手动输入大量命令要高效的多,所以让我们创建一个配置文件,取代我们之前使用 cli 命令执行的方式。

来自官网的一段话

webpack 在工作时,它会默认去根目录下找一个名为 webpback.config.js 的文件(如果找不到,则它会用一些默认设置)。

webpback.config.js 就是webpack的配置文件,在这个配置文件中,我们可以通过一个 导出一个 json对象去配置webpback的参数,让打包更加灵活。

1. 创建默认配置文件 webpack.config.js

位置

我们先指定一下打包模式 mode

module.exports = {
    mode: "development" // production(生产)
}
复制代码

接下来再次运行打包命令,查看产生的main.js文件的内容,对比与之间的变化。

  1. 黄色警告没有了,因为我们已经设置了 mode。
  2. 我们可以把 webpack 的配置文件想象成 webpack 是一个函数,它接受一个对象,通过对象来让 webapck 函数来产生我们想要的结果。

此文件的意义是导出一个配置项:用来配置 webpack 如何打包。

在操作层面,就是学习如何去使用这个文件。

mode模式:

  • development:开发模式(代码不会压缩 混淆)
  • production:生产模式(压缩,混淆,加密....... 不可读)

2. 指定配置文件(自定义配置文件名)

目的

为了实现多种打包模式,例如开发模式,生产模式,我们可以写在一个配置文件中但是它不利于维护。

我推荐把不同功能的配置文件单独分开写,通常工作中也是这样的。

在默认情况下,webpack会找一个名为 webpack.config.js的文件作为它的配置文件,但是,针对不同的场景,我们可以自行决采用哪个配置文件,换句话说,配置文件不一定必须叫webpack.config.js

下面,自已创建一个webpack.dev.js的文件用它来做配置文件,并使用它进行打包

1. 在根目录下创建自定义配置文件

在项目根目录下创建webpack.dev.js,内容如下:

module.exports = {
  mode: 'development',
  output:{
    filename:'bundle.js'
  }
}
复制代码

2. 使用这个文件进行打包的配置

基本格式
npx webpack --config webpack的配置文件 入口文件
复制代码
运行命令
npx webpack --config webpack.dev.js index.js
复制代码

3. 通过 package.json 中的 scripts 简化运行命令

基本格式
"scripts": {
    "自定义命令名": "要具体执行的代码",
  }
复制代码
示例
"scripts": {   
    "build": "webpack --config webpack.dev.js index.js"
 }
复制代码
运行命令
npm run build 
//相当于是 npx webpack --config webpack.dev.js  index.js
复制代码

4. 设置打包入口文件和出口路径

在webpack中:

  • 默认入口是:./src/index.js
  • 默认出口是:./dist/main.js。

1. 设置入口路径

我们在实际工作中入口文件往往不是 index.js 也许叫 app.js

调整目录结构

|-package.json
|-index.html
|-src/
|-src/js
|-------app.js
|-------tool.js
|-------tooles6.js
复制代码
  • 修改src/index.js的名字为src/js/app.js

  • 在webpack.config.js的配置项中添加 entry ,如下

  • module.exports = {
      mode: 'development', // 打包方式
      entry:'./src/js/app.js' // 入口文件
    }
    复制代码
  • 修改快速打包命令

    • "scripts": {
         "build": "webpack"
       }
      复制代码
    • 因为我们使用的是 webpack.config.js 所有这里不需要使用--config webpack.config.js 去指定配置文件。

  • 重新打包测试

npm run build
复制代码

2. 设置出口路径

  • 在webpack.config.js的配置项中添加 output ,如下

    • // 引入nodejs中的核心模块
      const path = require('path') 
      console.log(path.join(__dirname,'/build'))
      module.exports = {
          mode: "production",
          entry: './src/js/app.js', // 入口文件
          output: {
              "path": path.join(__dirname,'/build'), // 决定出口文件在哪里
              "filename": "bundle.js" // 设置出口文件的名字。默认情况下,它叫main.js
          }
      }
      复制代码
    • 说明:

      • output中的filename用来指定打包后的文件名字。
      • output中的path用来指定打包后的路径。注意:它必须是绝对路径。所以,这里引用path模块中的resolve方法来生成绝对路径。
      • 如果path中的路径不存在,它会自动创建一个默认的路径名称 dist
  • 重新打包测试

npm run build
复制代码

小结

  • webpack的配置文件默认名是webpack.config.js
  • 也可以单独指定 webpack 的配置文件来满足多种场景的需要。
  • 学习webpack就学习webpack.config.js的使用。
  • 把webpack的打包命令集成到script中可以简化打包命令,同时方便其他合作人员的使用。
  • 自行定义入口和出口文件

灵魂三问

​ 有什么用?

​ 打包

​ 为什么用它?

​ 工程化:前端任务重需要有工具来管理

​ 开发、上线

​ 怎么用?

​ 学习 webpack.config.js 不用记住,多看文档,仅仅需要记住最外面基本配置作用即可。

webpack-高级配置

1. loader

介绍

为什么用 loader?

webpack 在不使用loader的时候仅仅可以处理 .js 格式的文件,而我们项目中有着各种格式的文件,以及需要对 js文件进行进一步处理例如 es6 转 es5。

1.目的

通过loader 对要打包的文件进行语法转化。

2.作用

将一个个文件以字符串的形式读入,对其进行语法分析及进行转换。

3.原理

可以把 loader 理解成一个翻译员,把源文件经过转换后输出结果,并且一个文件还可以链式的多次翻译。

loader 也是一个模块,默认导出为一个 node 形式的函数,这个函数在 loader 进行资源转换时候调用,并通过 this上下文访问。

module.exports = function(source) {
  // source 为 compiler 传递给 Loader 的一个文件的原内容
  // 该函数需要返回处理后的内容,这里简单起见,直接把原内容返回了,相当于该`Loader`没有做任何转换
  return source;
};
复制代码

转换:一个Loader的职责是单一的,只需要完成一种转换。 如果一个源文件需要经历多步转换才能正常使用,就通过多个Loader去转换。 在调用多个Loader去转换一个文件时,每个Loader会链式的顺序执行, 第一个Loader将会拿到需处理的原内容,上一个Loader处理后的结果会传给下一个接着处理,最后的Loader将处理后的最终结果返回给Webpack。 所以,在你开发一个Loader时,请保持其职责的单一性,你只需关心输入和输出。

实例

1. 使用 css-loader ,style-loader 处理文件中的 .css 文件

准备

public.css

body,html{
    padding:0;
    font-size:14px;
}
复制代码

style.css

@import "public.css";
div {
  border:4px solid #ccc;
  width: 50%;
  height: 200px;
  margin:30px auto;
  box-shadow: 3px 3px 3px #ccc;
  background-color: #fff;
  text-align: center; 
}
复制代码

app.js 增加引入 css 文件

// node 模块化导入
const {updateDom} = require('./tool');
 // es6 模块化导入
import {log} from './tooles6';
// + 新增 css 文件引入
import './../css/style';

updateDom('app','传智播客')

log('测试webpack是否能识别es6的模块化')
复制代码

使用 webpack 打包

npm run bulid
复制代码

此时控制台

我们看到控制台报错,这里我们只需要注意 关键子 loader 以及文件格式.css ,由此可以推断出是缺少 css-loader

css-loader 安装

npm install css-loader -D
复制代码

-D devDependencies是开发时的依赖

css-loader 在webpack中配置

module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['css-loader']
            },
        ],
    }
}
复制代码

在 expors 的对象内部增加 module 对象 通过配置 rules 数组进行 loader 的配置

执行顺序 :从数组的最末端开始执行,也可以简单的理解为从右往左。

执行命令及结果

此时打开浏览器观看 样式并没有生效 css-loader 的作用就是帮助 webpack 读取 .css 文件,并打包进 bundle.js中,此时还需要 style-loader

安装

npm i style-loader -D
复制代码

使用

module.exports = {
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader','css-loader']
            },
        ],
    }
}
复制代码

完整代码:

const path = require('path') 
console.log(path.join(__dirname,'/build'))
module.exports = {
    mode: "production",
    entry: './src/js/app.js', // 入口文件
    output: {
        "path": path.join(__dirname,'/build'), // 决定出口文件在哪里
        "filename": "bundle.js" // 设置出口文件的名字。默认情况下,它叫main.js
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader','css-loader']
            },
        ],
    }
}
复制代码

我们看下输出的 .js 包

bundle.js中有一些js代码,它在运行时,会自动在.html文件中追加style标签,并输出样式。

扩展

eval("var api = __webpack_require__(/*! ../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js */ \"./node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js")
复制代码

再去node_modules\style-loader\dist\runtime\injectStylesIntoStyleTag.js 找下insertStyleElement这个方法,你就可以发现这个过程。

function insertStyleElement(options) {
  var style = document.createElement('style');
  var attributes = options.attributes || {};

  if (typeof attributes.nonce === 'undefined') {
    var nonce = typeof __webpack_nonce__ !== 'undefined' ? __webpack_nonce__ : null;

    if (nonce) {
      attributes.nonce = nonce;
    }
  }

  Object.keys(attributes).forEach(function (key) {
    style.setAttribute(key, attributes[key]);
  });

  if (typeof options.insert === 'function') {
    options.insert(style);
  } else {
    var target = getTarget(options.insert || 'head');

    if (!target) {
      throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");
    }

    target.appendChild(style);
  }

  return style;
}
复制代码

此时浏览器就可以渲染样式了。

这里大家要注意 loader 的配置顺序。


小节 css-loader 帮助webpack 把.css 打包进去 style-loader 把打包的 .css 进行转换通过函数以 style标签的形式插入到 html 中。

扩展小知识** @import 用来引入另一个 css 文件。

语法

@import url;
@import url list-of-media-queries;
@import [ <string> | <url> ] [ <media-query-list> ]?;
复制代码

解释

  • url:是一个表示要引入资源位置的 ](https://developer.mozilla.org/zh-CN/docs/Web/CSS/string) 或者 [ 。 这个 URL 可以是绝对路径或者相对路径。 要注意的是这个 URL 不需要指明一个文件; 可以只指明包名。
  • list-of-media-queries 是一个逗号分隔的 媒体查询 条件列表,决定通过URL引入的 CSS 规则 在什么条件下应用。如果浏览器不支持列表中的任何一条媒体查询条件,就不会引入URL指明的CSS文件。

实例

  • css文件中用法
/* 方法一*/
@import 'test.css';
/* 方法二*/
@import url(test.css);
/* @import url list-of-media-queries;*/
@import "common.css" screen, projection;
@import url('landscape.css') screen and (orientation:landscape);
复制代码
  • js 文件中用法
 import 'test.css';
复制代码
2. 使用 less-loader 处理 .less 文件

安装

npm i less-loader  -D
// 不用在安装 less
npm i less-loader less  -D
复制代码

less-loader: 加载 less 文件并且把 .less 语法的代码转换成 .css

配置

module.exports = {
    module: {
        rules: [
            {
                test:/\.less$/,
                use:['style-loader','css-loader','less-loader']
            }
        ],
    }
}
复制代码

完整代码

const path = require('path') 
console.log(path.join(__dirname,'/build'))
module.exports = {
    mode: "development", // development  production
    entry: './src/js/app.js', // 入口文件
    output: {
        "path": path.join(__dirname,'/build'), // 决定出口文件在哪里
        "filename": "bundle.js" // 设置出口文件的名字。默认情况下,它叫main.js
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader','css-loader']
            },
            {
                test:/\.less$/,
                use:['style-loader','css-loader','less-loader']
            }
        ],
    }
}
复制代码

这里大家要注意下 less 文件的 loader顺序

 use:['style-loader','css-loader','less-loader']
复制代码

原理:先执行 less-loader 加载 .less 并转换成 css 把转换的结果给 css-loader ,css-loader 把结果在处理给 style-loader , 如果只配置 less-loader webpback 无法识别 css 格式。因为每个 test 都是一个处理模块 webpack 不会把 test:/.css/ 的规则用来处理 /.less/

代码改造

index.less

 @import "style.css";

body{ 
  div {
    border:4px solid #ccc;
    width: 50%;
    height: 200px;
    margin:30px auto;
    box-shadow: 3px 3px 3px #ccc;
    background-color: #fff;
    text-align: center; 
  }
}
复制代码

app.js

// node 模块化导入
const {updateDom} = require('./tool');
// 引入 less 文件
import '../css/index.less'
// 引入 css 文件
// import './../css/style.css';
 // es6 模块化导入
import {log} from './tooles6';

updateDom('app','传智播客')

log('测试webpack是否能识别es6的模块化')
复制代码

执行打包命令并且在浏览器中查看

3. 使用 url-loader file-loader 处理图片资源

前端开发不可避免的使用各种图片资源

代码改造

index.less 文件

 @import "style.css";

body{ 
  div {
    border:4px solid #ccc;
    width: 50%;
    height: 200px;
    margin:30px auto;
    box-shadow: 3px 3px 3px #ccc;
    background-color: #fff;
    text-align: center; 
    background-image: url(./../img/webpack-png.png);
  }
}
复制代码

安装 url-loader

npm i url-loader - D
复制代码

配置

module.exports = {
    module: {
        rules: [
             {
                test:/\.png/,
                use:['url-loader']
            }
        ],
    }
}
复制代码

执行

npm run build
复制代码

结果

我们发现只有一个js文件,那是因为 url-loader 把图片文件转换成了 base 64。

优点:减少网络请求。

缺点: 增加了 js包大小。

base64 一般比图片会大一点点。

如何选择?

小文件可以转换成 base 64,大文件不推荐。

url-loader 高级配置

我们使用loader 的时候,之前是 use:['xxx-loader'],如果想详细的设置loader可以如下

通用规则

use:[
    {
        loader:'xxx-loader',
        options:{

        }}
]
复制代码

如果你不是很了解可以通过 npm 去找对应的loader,例如

配置完成后的代码

const path = require('path') 
console.log(path.join(__dirname,'/build'))
module.exports = {
    mode: "development", // development  production
    entry: './src/js/app.js', // 入口文件
    output: {
        "path": path.join(__dirname,'/build'), // 决定出口文件在哪里
        "filename": "bundle.js" // 设置出口文件的名字。默认情况下,它叫main.js
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader','css-loader']
            },
            {
                test:/\.less$/,
                use:['style-loader','css-loader','less-loader']
            },
            {
                test:/\.png/,
                use:[{
                    loader:'url-loader',
                    options:{
                        limit:3*1024 // 3* 1024b = 3kb
                    }
                }]
            }
        ],
    }
}
复制代码

执行 build结果如下:

这是因为我们通过配置 url-loder 使得它只处理 3k 一下的图片,并转换成 base64,如果需要处理大于 3kb的需要使用 file-loader 。

安装 file-loader

npm i file-loader -D
复制代码

执行代码结果

这个时候我们发现并没有 配置 file-loader 就可以直接起作用了。

注意

浏览器查看

此时页面上面并不会显示图片,因为 file-loader 仅仅把图片复制过去。这时候我们查看路径,浏览器中是找不到路径的。这时候右键查看图片路径,我们可以很清楚的看到我们的图片路径位置是不对的

原因

上述代码设置了 limit 选项,意思是当图片体积小于 8192 字节时,会转换成 base 编码字符串,当图片体积大于 8192 字节时,默认会使用 file-loader。

解决方案 (如果大家看着笔记去学习,这里建议了解下直接跳过,因为后面通过 webpack 新增的 plugin 配置就会解决这个问题,不要浪费时间在这里)

修改 css 引用路径为file-loader处理图片后的路径。

  1. 工具 mini-css-extract-plugin 参考下面的内容配置

但是 mini-css-extract-plugin 通常是项目打包的时候才会用到。

扩展配置

我们的 url-loader 功能强大,它可以处理多种格式的文件,那么怎么优化配置 呢?具体如下

{
    test:/(\.png|\.jpg|\.svg)/,
    use:[{
        loader:'url-loader',
        options:{
        limit:3*1024 // 3* 1024b = 3kb
        }
    }]
}
复制代码

其实就是使用正则表达式把我们想用 url-loader 处理的文件写在 test里面这样就可以匹配啦。

优化配置 通过配置 name 可以修改 打包之后图片的名称和输出位置

{
    test:/\.png/,
        use:[{
            loader:'url-loader',
            options:{
                limit:3*1024, // 3* 1024b = 3kb
                name:'img/[name].[ext]'
            }
        }]
}
复制代码

由于我们的 output 路径写的式 build 所以这里的name 可以成上面的样子,name 是原来文件名称 ext是文件类型

测试svg文件

代码改造

index.less

@import "style.css";
body{ 
  background: url(./../img/webpack-svg.svg);
  div {
    border:4px solid #ccc;
    width: 50%;
    height: 200px;
    margin:30px auto;
    box-shadow: 3px 3px 3px #ccc;
    background-color: #fff;
    text-align: center; 
    background-image: url(./../img/webpack-png.png);
  }  
}
复制代码

执行打包

因为我们的svg图片小于 3k 所以 url-loader 把svg资源转成了 base64 大到了js里面

loader 小结

如何使用

  1. 根据文件类型下载对应的loader。
  2. 配置loader。

2. plugin 插件

介绍

1. 目的

插件在于解决 loader 无法实现的其他事

2. 作用

plugin是用于扩展webpack的功能,

3. 常用 plugin 总结

html-webpack-plugin

功能:把我们自已写的.html文件复制到指定打包出口目录下,并引入相关的资源代码。

mini-css-extract-plugin

功能:这个插件帮助我们把css代码提取到一个独立的文件中(而不是以style的方式嵌在html文件中)。

clean-webpack-plugin

在生成打包文件之前,把目录清空掉。

实例

1. mini-css-extract-plugin

安装过程

  1. 下载插件
npm i mini-css-extract-plugin -D
复制代码
  1. 在配置文件中引入

webpack.config.js

const MiniCssExtractPlugin = require('mini-css-extract-plugin');
复制代码
  1. 修改 webpack.config.js 的 module.exports 中的 rules

    module.exports = {
        module:{
            rules:[
                 {
                     // 替换 style-loadr 为 {loader: MiniCssExtractPlugin.loader}这个配置是我们项目打包上线常用的写法。
                    test:/\.less$/,
                    use:[{loader: MiniCssExtractPlugin.loader},'css-loader','less-loader']
                },
            ]
        }
    }
    复制代码
  2. 在 webpack.config.js 的 module.exports 增加 plugins。所有的插件都需要在这里面new 一下

     plugins:[
            new MiniCssExtractPlugin({
                // [name], [hash] 是占位符
                // name: 表示入口文件的名称
                // hash: 一串随机值,是用于区别于本次打包与其它打包的过程。由于源文件有变化,则每次打包时hash都不同
                filename: '[name]-[hash].css',
            })
        ]
    复制代码

    完整代码

    const path = require('path') 
    +const MiniCssExtractPlugin = require('mini-css-extract-plugin');
    console.log(path.join(__dirname,'/build'))
    module.exports = {
        mode: "development", // development  production
        entry: './src/js/app.js', // 入口文件
        output: {
            "path": path.join(__dirname,'/build'), // 决定出口文件在哪里
            "filename": "bundle.js", // 设置出口文件的名字。默认情况下,它叫main.js       
        },
        module: {
            rules: [
                {
                    test: /\.css$/,
                    use: ['style-loader','css-loader']
                },
                {
                    test:/\.less$/,
       +             use:[{loader: MiniCssExtractPlugin.loader},'css-loader','less-loader']
                },
                {
                    test:/(\.png|\.jpg|\.svg)/,
                    use:[{
                        loader:'url-loader',
                        options:{
                            limit:3*1024, // 3* 1024b = 3kb                       
                        }
                    }]
                }
            ],
        },
    +    plugins:[
            new MiniCssExtractPlugin({
                // [name], [hash] 是占位符
                // name: 表示入口文件的名称
                // hash: 一串随机值,是用于区别于本次打包与其它打包的过程。由于源文件有变化,则每次打包时hash都不同
                filename: '[name]-[hash].css',
            })
        ]
    }
    复制代码

执行打包命令

注意

这时后我们的 index.html 路径是不对的

我们的index.html 没有引用,这时候打开浏览器是看不到样式的,这时候我看额可以手动修改下 css 文件的引用地址。

2. html-webpack-plugin
  1. 安装
npm i html-webpack-plugin -D
复制代码
  1. 在配置文件中引入。

webpack.config.js

const HtmlWebpackPlugin = require('html-webpack-plugin');
复制代码
  1. 在 webpack.config.js 的 plugins 中 new HtmlWebpackPlugin并配置
plugins: [
    new HtmlWebpackPlugin({ // 打包输出HTML
        minify: { // 压缩HTML文件
            removeComments: true, // 移除HTML中的注释
            collapseWhitespace: true, // 删除空白符与换行符
            minifyCSS: true// 压缩内联css
        },
        filename: 'index.html',
        template: path.resolve('./index.html') // 指定模块的位置
    })
]
复制代码

删除 html 中的引用

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <!-- <link rel="stylesheet" href="./src/css/style.css"> -->
</head>
<body>
    <div id="app"></div>
</body>
<!--
    不通过webpack打包
     <script src="tool.js"></script> 
    <script src="./index.js"></script>
-->
<!-- 使用webpack 打包生成的文件路径 -->
<!-- <script src="./build/bundle.js"></script> -->
</html>
复制代码

执行代码结果

build 里面多了一个 html。

删除HtmlWebpackPlugin 压缩的配置项

plugins: [
    new HtmlWebpackPlugin({ // 打包输出HTML       
        filename: 'index.html',
        template: path.resolve('./index.html') // 指定模块的位置
    })
]
复制代码

打包后的结果

我们发现 url-loader 之前处理路径有问题的背景图片也显示出来了。

这些配置项我们同样可以在 npm 包的网站中找到,不需要去记住。接下来我们在添加一个插件去巩固下我们的知识。

3. clean-webpack-plugin

下载插件

npm i clean-webpack-plugin -D
复制代码

配置文件webpack.config.js

const { CleanWebpackPlugin } = require('clean-webpack-plugin')
module.exports = {
    plugins: [
    new CleanWebpackPlugin()
]	
}

复制代码

执行效果

全部代码

const path = require('path') 
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
console.log(path.join(__dirname,'/build'))
module.exports = {
    mode: "development", // development  production
    entry: './src/js/app.js', // 入口文件
    output: {
        "path": path.join(__dirname,'/build'), // 决定出口文件在哪里
        "filename": "bundle.js", // 设置出口文件的名字。默认情况下,它叫main.js       
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader','css-loader']
            },
            {
                test:/\.less$/,
                use:[{loader: MiniCssExtractPlugin.loader},'css-loader','less-loader']
            },
            {
                test:/(\.png|\.jpg|\.svg)/,
                use:[{
                    loader:'url-loader',
                    options:{
                        limit:3*1024, // 3* 1024b = 3kb                       
                    }
                }]
            }
        ],
    },
    plugins:[
        new MiniCssExtractPlugin({
            // [name], [hash] 是占位符
            // name: 表示入口文件的名称
            // hash: 一串随机值,是用于区别于本次打包与其它打包的过程。由于源文件有变化,则每次打包时hash都不同
            filename: '[name]-[hash].css',
        }),
        new HtmlWebpackPlugin({ // 打包输出HTML
            minify: { // 压缩HTML文件
                removeComments: true, // 移除HTML中的注释
                collapseWhitespace: true, // 删除空白符与换行符
                minifyCSS: true// 压缩内联css
            },
            filename: 'index.html',
            template: path.resolve('./index.html') // 指定模块的位置
        }),
        new CleanWebpackPlugin()
    ]
}
复制代码

plugin 使用小结

plugin 用来增强 webpack 的能力

有了上面三个插件的使用经验我们总结下安装插件的步骤和注意点

  1. npm 包下载插件。
  2. 在配置文件中引入插件。
  3. 在 plugin的数组中 new 这个插件。

注意:

  1. 有些插件是直接导出的函数,而有些插件是导出的对象,例如const { CleanWebpackPlugin } = require('clean-webpack-plugin'),当我们引用npm 包报错时候可以去 npm 包官网查看下使用 demo。
  2. 所有的插件都一定会在 plugins 数组里面通过 new 实例化。
  3. 插件在 plugins 中的顺序不是它调用的顺序,它的调用顺序和 webpack 执行过程有关系。

3. webpack-dev-server

目的: 在开发过程中实时更新我们的代码。

如何配置?

  1. 使用 npm 下载包

    npm i webpack-dev-server  -D
    复制代码
  2. 在配置文件最外层配置

    module.exports = {
        // 配置 webpack-dev-server的选项
        devServer: {
            host: '127.0.0.1',  // 配置启动ip地址
            port: 8081,  // 配置端口
            open: true  // 配置是否自动打开浏览器
        }
        // 其它配置
    }
    复制代码
  3. 修改 package.json 的快速启动配置

     "scripts": {
        "build": "webpack",
    +    "dev":"webpack-dev-server"
      },
    复制代码

    执行新配置的命令

    npm run dev
    复制代码

    这时我们的浏览器就打开了,并且端口号是 8081,如果我们不想让我们的项目端口号和其他的项目冲突,可以去掉 port webpback 就会根据当前 系统端口占用情况自动生成一个端口号。

小结

webpack-dev-server 解决了我们开发过程中代码实时预览的问题,给我们的开发代来了方便,它的功能不仅仅如此,还可通过它配置跨越等功能。

3. webpoack 处理 .vue 文件

介绍

1 . 目的

通过webpack 可以处理打包 .vue 文件

配置

代码准备

vue 文件 /vuecomponents/App.vue

<template>
  <div>
    vue组件 {{title}}
  </div>
</template>

<script>
  export default {
    name: '',
    data() {
      return {
        title:'webpack-vue-这里的vue单文件组件'
      }
    }
  }
</script>

复制代码

/js/main.js

import Vue from "vue"
import App from '../vuecomponents/app.vue'
new Vue({
  render(h) {
    return h(App)
  },
}).$mount("#app")
复制代码

我们这里引用了 vue 所有要在 npm 中下载 vue

npm i vue -D
复制代码

分析

  1. 我们新增 main.js 所以要修改配置文件 entry
  2. 我们要让webpack 识别 .vue 所以要安装 vue-loader
  3. 需要解析 .vue 的模板所以要有 vue-template-compiler
  4. 需要处理 .vue 内部的 style 所有要有 vue-style-loader

安装依赖

npm i vue-loader  vue-template-compiler vue-style-loader -D
复制代码

修改配置 webpack.config.js

  1. 修改 entry

     entry: './src/js/main.js',
    复制代码
  2. 给.vue文件添加loader

  3. 添加VueLoaderPlugin

Vue-loader在15.*之后的版本都是 vue-loader的使用都是需要伴生 VueLoaderPlugin的。

vue-style-loader 和 之前的 file-loader类似不需要单独配置。

{
    // 如果是.vue文件,使用如下的loader
    test: /\.vue$/,
        loader: 'vue-loader'
}

复制代码
const VueLoaderPlugin = require('vue-loader/lib/plugin')

复制代码

上面这段代码是官网提供的配置实例

plugins:[
    new VueLoaderPlugin()
]

复制代码

完整代码

const path = require('path') 
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const VueLoaderPlugin = require('vue-loader/lib/plugin')
module.exports = {
    mode: "development", // development  production
    entry: './src/js/main.js', // 入口文件
    
    output: {
        "path": path.join(__dirname,'/build'), // 决定出口文件在哪里
        "filename": "bundle.js", // 设置出口文件的名字。默认情况下,它叫main.js       
    },
    module: {
        rules: [
            {
                test: /\.css$/,
                use: ['style-loader','css-loader']
            },
            {
                test:/\.less$/,
                use:[{loader: MiniCssExtractPlugin.loader},'css-loader','less-loader']
            },
            {
                test:/(\.png|\.jpg|\.svg)/,
                use:[{
                    loader:'url-loader',
                    options:{
                        limit:3*1024, // 3* 1024b = 3kb    
                        name:'img/[name].[ext]'                   
                    }
                }]
            },
            {
                // 如果是.vue文件,使用如下的loader
                test: /\.vue$/,
                    loader: 'vue-loader'
            }
        ],
    },
    plugins:[
        new MiniCssExtractPlugin({
            // [name], [hash] 是占位符
            // name: 表示入口文件的名称
            // hash: 一串随机值,是用于区别于本次打包与其它打包的过程。由于源文件有变化,则每次打包时hash都不同
            filename: '[name]-[hash].css',
        }),
        new HtmlWebpackPlugin({ // 打包输出HTML
            
            filename: 'index.html',
            template: path.resolve('./index.html') // 指定模块的位置
        }),
        new CleanWebpackPlugin(),
        new VueLoaderPlugin()
    ],
    devServer: {
        host: '127.0.0.1',  // 配置启动ip地址
        port: 8081,  // 配置端口
        open: true  // 配置是否自动打开浏览器
    }
}

复制代码

执行命令效果

小结

  1. 处理 .vue 我们已经分析了 就是需要loader。
  2. 由此可以得出 webpack 的模块化其实并不复杂,我们在使用它去为我们的项目打包的时候通过要处理的文件类型,目的去 npm 包网站上或者 webpack网站中找到对应的依赖包就可以
  3. 我们要掌握的是 webpack 的通常用法,和能够明白在打包过程中为什么会有错误,以及可以通过 webpack 提供的信息去配置。

总结

  1. webpack 是一个打包工具
  2. 在 webpack 的世界里一切皆模块。
  3. loader 帮助 webpack 去翻译不同的文件让 webpack 可以把它们打包
  4. plugin 插件完善了 webpack 打包功能
  5. vue-cli 也是基于 webpack 开发实现的
分类:
阅读
标签: