认识webpack、安装、配置

422 阅读18分钟

webpack

一、认识webpack

之前的开发程序不能直接放到服务器,通过工具打包转化,生成让浏览器更容易识别的代码。 打包工具 grunt/gulp/webpack是/rollup(Rollup 是一个 JavaScript 模块打包器[rollup.js 中文文档] )

webpack是前端模块化打包工具,模块概念,打包概念

webpack和node和npm的关系: webpack正常运行必须依赖于node环境,node环境为了可以正常的执行很多代码,必须包含各种依赖的包,有一个npm工具,用于管理node下的各种包

使用webpack之前必须安装node,

vue cli2 脚手架2里才能看到webpack的所有配置,用3的话配置被隐藏起来了。

1. 什么是webpack

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

  • 从本质上来讲,webpack是一个现代的JavaScript应用的静态模块打包工具。
  • 我们从两个点来解释上面这句话:模块打包

image.png

2. 前端模块化和打包

前端模块化:

  • 目前使用前端模块化的一些方案:AMD、CMD、CommonJS、ES6。
  • 在ES6之前,我们要想进行模块化开发,就必须借助于其他的工具,让我们可以进行模块化开发。
  • 并且在通过模块化开发完成了项目后,还需要处理模块间的各种依赖,并且将其进行整合打包。
  • 而webpack其中一个核心就是让我们可能进行模块化开发,并且会帮助我们处理模块间的依赖关系。
  • 而且不仅仅是JavaScript文件,我们的CSS、图片、json文件等等在webpack中都可以被当做模块来使用。
  • 这就是webpack中模块化的概念。 打包如何理解:
  • 理解了webpack可以帮助我们进行模块化,并且处理模块间的各种复杂关系后,打包的概念就非常好理解了。
  • 就是将webpack中的各种资源模块进行打包合并成一个或多个包(Bundle)。
  • 并且在打包的过程中,还可以对资源进行处理,比如压缩图片,将scss转成css,将ES6语法转成ES5语法,将TypeScript转成JavaScript等等操作。
  • 但是打包的操作似乎grunt/gulp也可以帮助我们完成,它们有什么不同呢?

模块化开发

最初JavaScript只做一些简单的工作,随着代码量的增多,通常将代码组织在多个js文件中,会发现难以维护,如:全局变量同名问题,js文件引入顺序执行顺序的问题。 为了避免各种问题,便于维护,出现了模块化。

  • 前端模块化的一些方案:AMD、CMD、CommonJS、ES6。 前三个需要底层的支撑,比如在webpack中就可以使用,webpack就可以作为底层的支撑(支持各种模块化如以上三个),因为webpack会对其代码转成浏览器可以支持识别的代码;而ES6是浏览器可以直接解析的。

开发用模块化开发,只需要用webpack打包一下,就会自动处理模块之间的依赖,就可以转成浏览器识别的文件

1) 匿名函数+模块出口

首先通过匿名函数解决重名问题;

image.png 其次当使用了匿名函数后,该js文件里的变量则为局部变量,其他文件无法访问。此时需要使用模块作为出口。

  1. 在匿名函数内部,定义一个对象。
  2. 给对象添加各种需要暴露到外面的属性和方法(不需要暴露的直接定义即可)。
  3. 最后将这个对象返回,并且在外面使用了一个MoudleA接受。

image.png

2) CommonJS

此语法在一些环境下才可使用,如:webpack

image.png

3)ES6的Modules(export/import)
export导出变量

image.png

export导出函数或类

image.png

export default 导入者自定义名称

image.png

import使用

image.png

index.html

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
<!-- 类型需要设置为module,只有type="module"才支持这种导入导出语法 -->
<script src="aaa.js" type="module"></script>
<script src="bbb.js" type="module"></script>
<script src="mmm.js" type="module"></script>
</body>
</html>

aaa.js

var flag = true

function sum(num1, num2) {
  return num1 + num2
}

if (flag) {
  console.log(sum(20, 30));
}

// 1.导出方式一:
export { flag, sum }

// 2.导出方式二:
export var num1 = 1000;
export var height = 1.88

// 3.导出函数/类
export function mul(num1, num2) {
  return num1 * num2
}

export class Person {
  run() {
    console.log('在奔跑');
  }
}

// 5.export default 导入者自己命名
// export default在同一个模块中,不允许同时存在多个
export default function (argument) {
  console.log(argument);
}

bbb.js

// 1.导入的{}中定义的变量
import {flag, sum} from "./aaa.js";

if (flag) {
  console.log('小明是天才, 哈哈哈');
  console.log(sum(20, 30));
}

// 2.直接导入export定义的变量
import {num1, height} from "./aaa.js";

console.log(num1);
console.log(height);

// 3.导入 export的function/class
import {mul, Person} from "./aaa.js";

console.log(mul(30, 50));

const p = new Person();
p.run()

// 4.导入 export default中的内容
import addr from "./aaa.js";

addr('你好啊');

// 5.统一全部导入 通过*可以导入模块中所有的export变量;给*起一个别名,方便后续的使用
// import {flag, num, num1, height, Person, mul, sum} from "./aaa.js";

import * as aaa from './aaa.js'

console.log(aaa.flag);
console.log(aaa.height);

4)AMD、CMD

3. webpack和grunt/gulp的对比

  • grunt/gulp的核心是Task
    • 我们可以配置一系列的task,并且定义task要处理的事务(例如ES6、ts转化,图片压缩,scss转成css)
    • 之后让grunt/gulp来依次执行这些task,而且让整个流程自动化。
    • 所以grunt/gulp也被称为前端自动化任务管理工具。
  • 我们来看一个gulp的task
    • 下面的task就是将src下面的所有js文件转成ES5的语法。
    • 并且最终输出到dist文件夹中。
    image.png
  • 什么时候用grunt/gulp呢?
    • 如果你的工程模块依赖非常简单,甚至是没有用到模块化的概念。
    • 只需要进行简单的合并、压缩,就使用grunt/gulp即可。
    • 但是如果整个项目使用了模块化管理,而且相互依赖非常强,我们就可以使用更加强大的webpack了。
  • 所以,grunt/gulp和webpack有什么不同呢?
    • grunt/gulp更加强调的是前端流程的自动化,模块化不是它的核心。
    • webpack更加强调模块化开发管理,而文件压缩合并、预处理等功能,是他附带的功能。

二、webpack的安装

image.png

三、webpack的起步

1. 准备工作,创建文件

创建如下文件和文件夹:
文件和文件夹解析:

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

2. js文件打包(webpack src/main.js dist/bundle.js)

  • 现在的js文件中使用了模块化的方式进行开发,他们不可以直接使用。 因为如果直接在index.html引入这两个js文件,浏览器并不识别其中的模块化代码。
  • 另外,在真实项目中当有许多这样的js文件时,我们一个个引用非常麻烦,并且后期非常不方便对它们进行管理。
    我们应该怎么做呢?使用webpack工具,对多个js文件进行打包。
    我们知道,webpack就是一个模块化的打包工具,所以它支持我们代码中写模块化,可以对模块化的代码进行处理。
  • 另外,如果在处理完所有模块之间的关系后,将多个js打包到一个js文件中,引入时就变得非常方便了。
  • 打包后会在dist文件下,生成一个bundle.js文件。将这个js文件在index.html中引入即可

如何打包呢?使用webpack的指令即可

webpack src/main.js dist/bundle.js

image.png

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

3. 配置入口和出口(webpack)

由于每次使用webpack的命令webpack ./src/main.js ./dist/bundle.js都需要写上入口和出口作为参数,就非常麻烦,有没有一种方法可以将这两个参数写到配置中,在运行时,直接读取呢?

  1. 就是创建一个webpack.config.js文件,在文件中配置入口和出口
  2. 终端输入npm init 初始化,一直回车生成一个package.json文件
  3. 在终端输入 npm install,在当前文件中安装package.json中所有的依赖
  4. 在终端输入 webpack 进行打包,当即在dist文件夹下生成一个bundle.js文件

image.png

image.png

新建一个webpack.config.js文件,配置webpack的出口和入口
出口是个对象类型:路径+文件名
入口是生成的js文件

1、需要动态获取path路径,需要用到node语法。导入path模块 会去node对应的包里找;这时候需要pah这个包,那么就需要装个包,终端输入:npm init,一直回车生成package.json文件
当package.json里面需要依赖另外的东西的话,需要npm install,根据package.json里面所有的依赖,帮助我们在当前文件夹下安装一些东西。
2、出口的path模块中有个resolve函数,把两个路径拼接到一起。path: path.resolve(__dirname, 'dist'),
  __dirname是一个全局变量,是node上下文里自带的一个全局变量,保存的就是当前webpack.config.js文件所在的路径,把当前路径拼接一个dist,整个路径就有了,此时这个路径就是个绝对路径。
3、将入口的东西和出口的东西放到一个配置里。此时只需要在终端输入:webpack,即可进行打包。 不需要再输入:webpack ./src/main.js ./dist/bundle.js

四、webpack的配置

4. 局部安装webpack(node_modules/.bin/webpack)

  • 目前,我们使用的webpack是全局的webpack,如果我们想使用局部来打包呢?
    因为一个项目往往依赖特定的webpack版本,全局的版本可能跟这个项目的webpack版本不一致,导出打包出现问题。 所以通常一个项目,都有自己局部的webpack。

  • 第一步,项目中需要安装自己局部的webpack
    这里我们让局部安装webpack3.6.0 Vue CLI3中已经升级到webpack4,但是它将配置文件隐藏了起来,所以查看起来不是很方便。
    npm install webpack@3.6.0 --save-dev

  • 第二步,通过node_modules/.bin/webpack启动webpack打包 node_modules/.bin/webpack

image.png

5. package.json中定义启动(npm run build)

  • 可以在package.json的scripts中定义自己的执行脚本
  • package.json中的scripts的脚本在执行时,会按照一定的顺序寻找命令对应的位置。
    首先,会寻找本地的node_modules/.bin路径中对应的命令。
    如果没有找到,会去全局的环境变量中寻找。
    如何执行我们的build指令呢?npm run build

image.png

image.png

4、如果通过npm管理的话,通常使用npm run build进行打包, 那么如何将npm run build和webpack 对应起来呢;将webpack映射到npm run build的命令。

package.json中scripts脚本,当在终端执行npm run test的时候,会在到scripts中找test,执行test对应的内容
npm run build 的时候就会去找scripts中的build

执行webpack只要在终端执行的命令,用的都是全局安装的webpack, 当在本地单独安装了webpack后,并在package.json的scripts中定义个脚本,此时在终端执行的命令用的就是本地的webpack

本地的webpack是4.11.5的版本,这个项目使用的3.6.0的版本, 此时在终端执行命令时,用本地4.0的去打包本项目3.0的配置,为了避免打包出错, 需要在本地单独安装一个3.0的webpack:npm install webpack@3.6.0 --save-dev

devDependencies开发时依赖,webpack就是一个在打包完没有用的东西,所以在安装的后面加上 --save-dev
dependencies运行时依赖,在打包完还要用的东西放在这里

学完以上,在之后项目开发js时,就可随意使用模块化进行开发。

五、webpack核心loader的使用

1. 在webpack里去处理css文件

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

  • webpack用来做什么呢?
      在我们之前的实例中,我们主要是用webpack来处理我们写的js代码,并且webpack会自动处理js之间相关的依赖。
       但是,在开发中我们不仅仅有基本的js代码处理,我们也需要加载css、图片,也包括一些高级的将ES6转成ES5代码,将TypeScript转成ES5代码,将scss、less转成css,将.jsx、.vue文件转成js文件等等。
      对于webpack本身的能力来说,对于这些转化是不支持的。
      那怎么办呢?给webpack扩展对应的loader就可以啦。

  • loader使用过程:
       步骤一:通过npm安装需要使用的loader(不同的loader处理不同的文件)
       步骤二:在webpack.config.js中的modules关键字下进行配置

  • 大部分loader我们都可以在webpack的官网中找到,并且学习对应的用法。

      把css当作一个模块打包到bundle.js中,到时候只需要引用这一个文件就好

    image.png

  1. css文件准备
    如上图,在src目录中创建一个css文件,创建normal.css文件
    此时,normal.css并不会生效,没有引用。
    在入口文件main.js中引入,webpack会从入口开始查找其他依赖文件
    此时打包会报错,加载normal.css文件必须有对应的loaderimage.png

  2. css-loader 和 style-loader 下载
    webpack中文网loader使用
    npm install --save-dev css-loader
    npm install --save-dev style-loader

  3. webpack.config.js配置

    const path = require('path')
    
    module.exports = {
      entry: './src/main.js',
      output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'bundle.js',
        publicPath: 'dist/'
      },
      module: {
        rules: [
          {
            // 正则,\.对.进行转义;$结尾,匹配所有的css文件
            test: /\.css$/,
            // css-loader只负责将css文件进行加载
            // style-loader负责将样式添加到DOM中
            // 使用多个loader时, 是从右向左
            use: [ 'style-loader', 'css-loader' ]
          },
        ]
      }
    }
    
  4. npm sun build 打包,运行index.html查看效果

    webpack总结视频

2. 在webpack里去处理less文件

  1. 安装npm install --save-dev less-loader less

  2. 添加一个rules选项,用于处理.less文件

  3. npm sun build 打包,运行index.html查看效果

    image.png

3. 在webpack里去处理图片文件

  1. 安装npm install --save-dev url-loader 处理小图

  2. 安装npm install --save-dev file-loader处理大图

  3. 添加一个rules选项

  4. 配置publicPath: 'dist/',后续使用vue需要改掉

  5. 修改文件名称options: { limit: 8192, name: 'img/[name].[hash:8].[ext]' },

  6. npm sun build 打包,访问index.html查看效果

    image.png

    图片文件处理 – 修改文件名称

    image.png

4. ES6语法处理,babel将ES6转成ES5

  1. 直接使用babel对应的loader,安装babel-loader

  2. 配置webpack.config.js文件

  3. 重新打包,查看bundle.js文件,发现其中的内容变成了ES5的语法

    image.png

六、webpack中配置Vue

1. 引入vue.js

  1. 安装,引入vue,使用,打包

  2. 报错,由于runtime-only版本的Vue无法编译template,配置webpack

    image.png

    image.png

2. el和template区别

  1. 我们定义了el属性,用于和index.html中的#app进行绑定;用于指定Vue要管理的DOM,可以帮助解析其中的指令、事件监听等等。

  2. 在使用vue实例时,同时写了el和template的话,template模板的内容会替换掉挂载的对应el的模板。

  3. 好处是不需要再去修改index.html的代码,index.html就是固定的了。只需要在template中写入对应的标签即可。

    image.png

3. vue组件化开发引入

  1. 如果随着代码的增多,template中的代码就越来越多,这时候就需要抽取template的代码。
    将显示内容抽离成对象注册为组件使用

    image.png

  2. 将显示内容单独放入一个文件并导出,此时模版和js代码没有分离

    image.png 一个组件以一个js对象的形式进行组织和使用的时候是非常不方便的

    •   一方面编写template模块非常的麻烦
      
    • 另外一方面如果有样式的话,我们写在哪里比较合适呢?
      

    现在,我们以一种全新的方式来组织一个vue的组件,是否可以正确加载?

  3. 将显示内容放入一个vue文件中,将模版和js进行分离。
    此时再引入main.js,打包后报错,是因为无法编译vue文件,需要安装相关loader,然后在webpack中配置

    • 安装vue-loader和vue-template-compiler
      npm install vue-loader vue-template-compiler --save-dev
      
    • 修改webpack.config.js的配置文件:
      

    一旦改掉了package.json中的内容,就需要重新npm install,重新安装依赖

    image.png

  4. 将子组件导入父组件中显示

    image.png

七、plugin插件的使用

认识plugin

  • plugin是什么?
    • plugin是插件的意思,通常是用于对某个现有的架构进行扩展。
    • webpack中的插件,就是对webpack现有功能的各种扩展,比如打包优化,文件压缩等等。
  • loader和plugin区别
    • loader主要用于转换某些类型的模块,它是一个转换器。
      (用于加载某些文件对某种文件进行转化加载的时候,如css文件、vue文件)
    • plugin是插件,它是对webpack本身的扩展,是一个扩展器。
  • plugin的使用过程:
    • 步骤一:通过npm安装需要使用的plugins(某些webpack已经内置的插件不需要安装)
    • 步骤二:在webpack.config.js中的plugins中配置插件。

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

添加版权的Plugin(BannerPlugin插件)

  • 我们先来使用一个最简单的插件,为打包的文件添加版权声明
    该插件名字叫BannerPlugin,属于webpack自带的插件。

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

    image.png

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

    image.png

打包html的plugin(BannerPlugin插件)

  • 目前,我们的index.html文件是存放在项目的根目录下的。
    • 我们知道,在真实发布项目时,发布的是dist文件夹中的内容,但是dist文件夹中如果没有index.html文件,那么打包的js等文件也就没有意义了。
    • 所以,我们需要将index.html文件打包到dist文件夹中,这个时候就可以使用HtmlWebpackPlugin插件
  • HtmlWebpackPlugin插件可以为我们做这些事情:
    • 自动生成一个index.html文件(可以指定模板来生成)
    • 将打包的js文件,自动通过script标签插入到body中
  • 步骤:
    1. 安装HtmlWebpackPlugin插件
      npm install html-webpack-plugin --save-dev

    2. 使用插件,修改webpack.config.js文件中plugins部分的内容如下:
      这里的template表示根据什么模板来生成index.html
      另外,我们需要删除之前在output中添加的publicPath属性
      否则插入的script标签中的src可能会有问题

      image.png

js压缩的Plugin(uglifyjs-webpack-plugin插件)

目的是:把原来很工整的代码丑化压缩
  会把所有的空格删掉,以减小文件的大小
  将变量的名字用另外一些简单的符号代替
  会将声明版权的注释也删掉,这个和添加版权只能使用一个

  • 在项目发布之前,我们必然需要对js等文件进行压缩处理

    • 这里,我们就对打包的js文件进行压缩
    • 我们使用一个第三方的插件uglifyjs-webpack-plugin,并且版本号指定1.1.1,和CLI2保持一致。
    • 本来webpack自带了一个对代码进行压缩的插件,CLI2使用时报错,所以使用这个插件
  • 步骤

    1. 安装插件
      npm install uglifyjs-webpack-plugin@1.1.1 --save-dev

    2. 修改webpack.config.js文件,使用插件。查看打包后的bunlde.js文件,是已经被压缩过了。

      image.png

八、搭建本地服务器

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

步骤:

  • 不过它是一个单独的模块,在webpack中使用之前需要先安装它。cli2里使用的版本。
    npm install --save-dev webpack-dev-server@2.9.1
    此时通过执行 webpack-dev-server 即可运行

  • 配置webpack.config.js文件

    • devserver也是作为webpack中的一个选项,选项本身可以设置如下属性:
      • contentBase:为哪一个文件夹提供本地服务,默认是根文件夹,我们这里要填写./dist
      • port:端口号
      • inline:页面实时刷新
      • historyApiFallback:在SPA页面中,依赖HTML5的history模式
  • 配置package.json里的scripts:--open参数表示直接打开浏览器

    image.png

九、 webpack配置分离(webpack-merge插件)

  • 问题:webpack所有的配置都在webpack.config.js进行,当配置过多时,不好维护,并且需要手动修改不同环境需要依赖的配置。

    image.png

  • 解决:此时将webpack的配置分成三个文件,新建build文件夹及如下三个js文件

    • base.config.js 生产时开发时都需要的放在这个文件里
    • prod.config.js 生产环境需要的内容
    • dev.config.js 开发时需要的内容
  • 安装webpack-merge插件,属于开发依赖 --save-dev
    npm install webpack-merge --save-dev

    该插件可以帮助我们将prod.config.js和dev.config.js两个配置文件进行合并。此时webpack.config.js就可以删除掉了

    • 现在执行package.json里的脚本的时候会发生什么?
      npm run build 报错。 没有配置文件,配置文件应该被命名为webpack.config.js

      image.png

    • 需要在脚本里加上,指定使用哪个文件,自动找只会找webpack.config.js固定的文件

      "scripts": {
          "build": "webpack --config ./build/prod.config.js",
          "dev": "webpack-dev-server --open --config ./build/dev.config.js"
        },
      

      image.png

    • 此时再npm run build 打包成功,但是没有打包到dist文件夹里,打包到build/dist文件夹里。
      希望可以打包到项目根目录下的dist文件夹里。修改打包路径

      image.png

内容来自视频:最全最新Vue、Vuejs教程,从入门到精通