webpack学习一

网页中的静态资源:

JS:.js .jsx .coffee .ts(TypeScript 类 C# 语言)

CSS:.css .less .sass .scss

Images:.jpg .png .gif .bmp .svg

字体文件(Fonts):.svg .ttf .eot .woff .woff2

模板文件:.ejs .jade .vue

网页中引入的静态资源多了会存在什么问题:

1. 网页加载速度慢, 因为 我们要发起很多的二次请求;

2. 要处理错综复杂的依赖关系

如何解决上述问题:

1. 合并(减少二次请求)、压缩(提高加载速度)、精灵图(减少二次请求)、图片的Base64编码(会随着html代码加载出来,不要通过src属性再去请求资源)

2. 可以使用requireJS、也可以使用webpack可以解决各个包之间的复杂依赖关系;

什么是webpack?

webpack 是前端的一个项目构建工具,它是基于 Node.js 开发出来的一个前端工具;

如何完美实现上述的2种解决方案(gulp和webpack的区别):

1. 使用Gulp, 是基于 task 任务的;

2. 使用Webpack, 是基于整个项目进行构建的;

借助于webpack这个前端自动化构建工具,可以完美实现资源的合并、打包、压缩、混淆等诸多功能。

webpack安装的两种方式

1. 运行`npm i webpack -g`全局安装webpack,这样就能在全局使用webpack的命令

2. 在项目根目录中运行`npm i webpack --save-dev`安装到项目依赖中

初步使用webpack打包构建列表隔行变色案例

新建一个文件夹webpackStudy,并在该文件下创建dist(放置项目发布好之后的文件)、src(放置项目源代码文件)文件夹

运行`npm init -y`初始化项目,使用npm管理项目中的依赖包

使用`cnpm i jquery --save`安装jquery类库

编写好index.html的代码

  • 这是第1个li
  • 这是第2个li
  • 这是第3个li
  • 这是第4个li
  • 这是第5个li
  • 这是第6个li
  • 这是第7个li
  • 这是第8个li
  • 这是第9个li
  • 这是第10个li

编辑好main.js的代码

// 导入 Jquery
// import *** from *** 是ES6中导入模块的方式
// 由于 ES6的代码,太高级了,浏览器解析不了,所以,这一行执行会报错
import $ from 'jquery'
$(function () {
  $('li:odd').css('backgroundColor', 'yellow')
  $('li:even').css('backgroundColor', function () {
    return '#' + 'D97634'
  })
})

直接在页面上引用`main.js`会报错,因为浏览器不认识`import`这种高级的JS语法,需要使用webpack进行处理,webpack默认会把这种高级的语法转换为低级的浏览器能识别的语法;

运行`webpack 入口文件路径 输出文件路径`对`main.js`进行处理:

webpack src/js/main.js dist/bundle.js

中间可能会报错 Cannot find module 'webpack' 或者还需要安装其他的包,需要执行命令

npm install --save-dev webpack-cli
cnpm install --save-dev webpack
cnpm install webpack-dev-server

然后报了下面的错误

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/concepts/mode/

webpack学习一_第1张图片

更改指令

webpack ./src/main.js --output ./dist/bundle.js --mode development

webpack学习一_第2张图片

经过这个演示,可以明确Webpack能够做什么事情

1. webpack 能够处理 JS 文件的互相依赖关系(之前js文件里面很难引入外部js文件,除非使用es6);

2. webpack 能够处理JS的兼容问题,把 高级的、浏览器不是别的语法,转为 低级的,浏览器能正常识别的语法

webpack最基本的配置文件的使用:

当更改main.js里面的代码,main.js新产生的代码会不起作用,在这时需要在项目的根目录下面新建一个文件webpack.config.js(需要这个文件的另一个原因如果main.js里面的代码更新,但是在dist里面的bundle.js文件会得不到更新,而index.html文件里面是引用的是bundle.js这个文件所以会让main.js里面产生的新的代码发挥不了作用,还是需要再使用指令webpack src/js/main.js dist/bundle.js,为了简化这个过程也需要使用的这个配置文件),因为webpack是基于node.js构建的所以在这个配置文件里面可以使用node.js来编码

比如讲main.js文件里面的

$('li:odd').css('backgroundColor', 'yellow')

改为

$('li:odd').css('backgroundColor', 'red')

还需要在控制台重复输入

webpack ./src/main.js --output ./dist/bundle.js --mode development

但是新建了webpack.config.js文件以后:

const path = require('path')

// 这个配置文件,起始就是一个 JS 文件,通过 Node 中的模块操作,向外暴露了一个 配置对象
module.exports = {
  // 在配置文件中,需要手动指定 入口 和 出口
  entry: path.join(__dirname, './src/main.js'),// 入口,表示,要使用 webpack 打包哪个文件
  output: { // 输出文件相关的配置
    path: path.join(__dirname, './dist'), // 指定 打包好的文件,输出到哪个目录中去
    filename: 'bundle.js' // 这是指定 输出的文件的名称
  }
}

只需要在控制台输入

webpack

webpack学习一_第3张图片

当我们在 控制台,直接输入 webpack 命令执行的时候,webpack 做了以下几步:

1. 首先,webpack 发现,我们并没有通过命令的形式,给它指定入口和出口

2. webpack 就会去 项目的 根目录中,查找一个叫做 `webpack.config.js` 的配置文件

3. 当找到配置文件后,webpack 会去解析执行这个 配置文件,当解析执行完配置文件后,就得到了 配置文件中,导出的配置对象

4. 当 webpack 拿到 配置对象后,就拿到了 配置对象中,指定的 入口 和 出口,然后进行打包构建;

webpack-dev-server的基本使用

由于每次重新修改代码之后,都需要手动运行webpack打包的命令,比较麻烦,所以使用`webpack-dev-server`来实现代码实时打包编译,当修改代码之后,会自动进行打包构建。

运行cnpm install webpack-dev-server --save-dev把这个工具安装到项目的本地开发依赖,注意: webpack-dev-server 这个工具,如果想要正常运行,要求,在本地项目中(不是指全局),必须安装 webpack

安装完毕后,这个 工具的用法, 和 webpack 命令的用法,完全一样

由于,我们是在项目中,本地安装的 webpack-dev-server , 所以,无法把它当作 脚本命令,在powershell 终端中直接运行;(只有那些 安装到 全局 -g 的工具,才能在 终端中正常执行)

这时需要在package.json文件的scripts对象中加入dev属性

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "webpack-dev-server"
  }

然后执行npm run dev即可

webpack学习一_第4张图片

webpack学习一_第5张图片

但是从上图的运行效果来看,改变了main.js文件页面没有对应的改变,原因在于

webpack学习一_第6张图片

webpack-dev-server 帮我们打包生成的 bundle.js 文件存放到了当前目录下面,而不是在以前的dist文件下面,所以index.html引用外部js文件的src属性需要由

变为

webpack学习一_第7张图片

webpack-dev-server 帮我们打包生成的 bundle.js 文件,并没有存放到 实际的 物理磁盘上;而是,直接托管到了 电脑的内存中,所以,我们在 项目根目录中,根本找不到 这个打包好的 bundle.js;

我们可以认为, webpack-dev-server 把打包好的 文件,以一种虚拟的形式,托管到了 咱们项目的 根目录中,虽然我们看不到它,但是,可以认为, 和 dist src node_modules 平级,有一个看不见的文件,叫做 bundle.js

webpack-dev-server的常用命令

配置 dev-server 命令参数的第一种形式:

要使用webpack-dev-server的常用命令,需要在package.json文件的scripts对象中加入属性(例如dev2):

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev2": "webpack-dev-server --open --port 3000 --contentBase src --hot",
    "dev": "webpack-dev-server"
}

--open表示自动打开浏览器

--port 3000表示认的端口号是8080,如果需要8080端口被占用,就需要改端口,这里将端口号改为3000

--contentBase src表示默认进入src,而不是进入当前目录webpackStudy

--hot表示完成自动刷新(热重载、热更新),不会每次修改代码后重复生成bundle.js文件,减少不必要的代码(bundle.js里面和未修改前一样的代码)更新,可以实现浏览器的无刷新的重载,不需要我们自己在浏览器上手动刷新。

webpack学习一_第8张图片

webpack学习一_第9张图片

配置 dev-server 命令参数的第二种形式:

在webpack.config.js里面多加一个对象

devServer: { // 这是配置 dev-server 命令参数的第二种形式,相对来说,这种方式麻烦一些
    //  --open --port 3000 --contentBase src --hot
    open: true, // 自动打开浏览器
    port: 3000, // 设置启动时候的运行端口
    contentBase: 'src', // 指定托管的根目录
    hot: true // 启用热更新 的 第1步
}

html-webpack-plugin的两个基本作用

将index.html加入到内存

运行`cnpm install html-webpack-plugin --save-dev`安装到开发依赖

webpack学习一_第10张图片

修改`webpack.config.js`配置文件

// 导入处理路径的模块
var path = require('path');
// 导入在内存中生成 HTML 页面的 插件
// 只要是插件,都一定要 放到 plugins 节点中去
// 这个插件的两个作用:
//  1. 自动在内存中根据指定页面生成一个内存的页面
//  2. 自动,把打包好的 bundle.js 追加到页面中去
var htmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
    entry: path.resolve(__dirname, 'src/js/main.js'), // 项目入口文件
    output: { // 配置输出选项
        path: path.resolve(__dirname, 'dist'), // 配置输出的路径
        filename: 'bundle.js' // 配置输出的文件名
    },
    plugins: [ // 配置插件的节点
      //   new webpack.HotModuleReplacementPlugin(), // new 一个热更新的 模块对象, 这是 启用热更新的第 3 步
      new htmlWebpackPlugin({ // 创建一个 在内存中 生成 HTML  页面的插件
          template: path.join(__dirname, './src/index.html'), // 指定 模板页面,将来会根据指定的页面路径,去生成内存中的 页面
          filename: 'index.html' // 指定生成的页面的名称
      })
    ]
}

这个插件的两个作用:

1. 自动在内存中根据指定页面生成一个内存的页面

2. 自动,把打包好的 bundle.js 追加到页面中去,所以磁盘中的html页面不引入bundle.js也没关系,内存中的html页面会补上引用(如下图)

对比磁盘中的index.html文件和内存中的index.html文件:

webpack学习一_第11张图片

loader配置和使用

导入 CSS样式表

index.css文件:

li{
  list-style: none;
}

在main.js里面使用 import 语法,导入 CSS样式表(如果在html文件里面引用,css 会发起二次请求,会影响网页的加载速度)

import './css/index.css'

会报错

webpack学习一_第12张图片

因为webpack, 默认只能打包处理 JS 类型的文件,无法处理 其它的非 JS 类型的文件;如果要处理 非JS类型的文件,我们需要手动安装一些 合适 第三方 loader 加载器;

 首先需要安装 cnpm install style-loader css-loader --save-dev

webpack学习一_第13张图片

打开 webpack.config.js 这个配置文件,在 里面,新增一个 配置节点,叫做 module, 它是一个对象;在 这个 module 对象身上,有个 rules 属性,这个 rules 属性是个 数组(在webpack里面基本所有结尾带s的单词对应的都是数组);这个数组中,存放了,所有第三方文件的 匹配和 处理规则

module: { // 这个节点,用于配置 所有 第三方模块 加载器 
    rules: [ // 所有第三方模块的 匹配规则
      { test: /\.css$/, use: ['style-loader', 'css-loader'] }, //  配置处理 .css 文件的第三方loader 规则
    ]
}

注意:`use`表示使用哪些模块来处理`test`所匹配到的文件;`use`中相关loader模块的调用顺序是从后向前调用的;当最后的一个 loader 调用完毕,会把 处理的结果,直接交给 webpack 进行 打包合并,最终输出到 bundle.js 中去

webpack学习一_第14张图片

导入 less文件

运行`cnpm install sass-loader node-sass --save-dev`

在`webpack.config.js`中添加处理sass文件的loader模块:
```
{ test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] }
```

导入 sass文件

运行`cnpm install sass-loader node-sass --save-dev`
在`webpack.config.js`中添加处理sass文件的loader模块:
```
{ test: /\.scss$/, use: ['style-loader', 'css-loader', 'sass-loader'] }
```

webpack 处理第三方文件类型的过程:

1. 发现这个 要处理的文件不是JS文件,然后就去 配置文件中,查找有没有对应的第三方 loader 规则

2. 如果能找到对应的规则, 就会调用 对应的 loader 处理 这种文件类型;

3. 在调用loader 的时候,是从后往前调用的;

4. 当最后的一个 loader 调用完毕,会把 处理的结果,直接交给 webpack 进行 打包合并,最终输出到 bundle.js 中去

处理css中的路径,url-loader的使用

在index.html中新增一个盒子,并通过css样式设置该盒子的背景

index.scss:

.box{
    position: relative;
    top: 0px;
    left: 40px;
    width: 440px;
    height: 240px;
    // 默认情况下,webpack 无法 处理 CSS 文件中的 url 地址,不管是图片还是 字体库, 只要是 URL 地址,都处理不了
    background: url('../images/nana1.jpg');
    background-size: cover;
  }

会报错:

webpack学习一_第15张图片

webpack学习一_第16张图片

运行`cnpm install url-loader file-loader --save-dev`

在`webpack.config.js`中添加处理url路径的loader模块:

```

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

```

webpack学习一_第17张图片

审查图片发现图片变成了Base64编码,这样减少了二次请求:

webpack学习一_第18张图片

怎样才能使图片不变成base64编码?

首先需要查看图片的属性

webpack学习一_第19张图片

然后修改一下匹配规则:

{ test: /\.(jpg|png|gif|bmp|jpeg)$/, use: 'url-loader?limit=179206' }

limit 给定的值,是图片的大小,单位是 byte, 如果我们引用的 图片,大于或等于给定的 limit值,则不会被转为base64格式的字符串, 如果 图片小于给定的 limit 值,则会被转为 base64的字符串

webpack学习一_第20张图片

但是发现图片的名称不一样了变成了一串字符串(哈希值),是为了防止图片重名

如果不想图片名称变成一串哈希值,还需要修改一下匹配规则

{ test: /\.(jpg|png|gif|bmp|jpeg)$/, use: 'url-loader?limit=179206&name=[name].[ext]' }

[name]表示之前图片叫什么名字,现在图片还叫那个名字

[ext]表示之前图片文件的后缀名叫什么,现在图片文件的后缀名还是那个后缀名

webpack学习一_第21张图片

在index.html新增一个盒子box2

在文件目录下新建一个存放图片的images2,在里面存放和images文件里面图片内容不一样但是图片名称相同的图片文件

在index.scss文件里面新增样式

.box2{
    position: relative;
    top: 10px;
    left: 40px;
    width: 440px;
    height: 240px;
    // 默认情况下,webpack 无法 处理 CSS 文件中的 url 地址,不管是图片还是 字体库, 只要是 URL 地址,都处理不了
    background: url('../images2/nana1.jpg');
    background-size: cover;
  }

结果会发现box和box2里面的图片内容变成一样的了,但是box和box2的图片内容应该是不一样的,就是因为images和images2的图片重名了,webpack将图片打包到根目录时,解析index.scss时,首先将images里的图片放到根目录上,继续解析时发现了图片名称一样的images2的图片,于是便会覆盖之前存放的images的图片

webpack学习一_第22张图片

解决上面的问题,同样要修改匹配规则:

{ test: /\.(jpg|png|gif|bmp|jpeg)$/, use: 'url-loader?limit=179206&name=[hash:8]-[name].[ext]' }

[hash:8]表示在图片名称前再加8位hash值,这样就能避免因为图片重名出现的上面的问题

webpack学习一_第23张图片

webpack学习一_第24张图片                   webpack学习一_第25张图片

使用url-loader处理字体图标

安装bootstrap,使用命令cnpm install bootstrap --save

在index.html里面加入字体图标

在main.js里面加入

import 'bootstrap/dist/css/bootstrap.css'

如果要通过路径的形式,去引入 node_modules 中相关的文件,可以直接省略 路径前面的 node_modules 这一层目录,直接写 包的名称,然后后面跟上具体的文件路径

不写 node_modules 这一层目录 ,默认 就会去 node_modules 中查找

在webpack.config.js里面加入匹配规则:

{ test: /\.(ttf|eot|svg|woff|woff2)$/, use: 'url-loader' }

babel的配置

在main.js中使用es6中Class

// class 关键字,是ES6中提供的新语法,是用来 实现 ES6 中面向对象编程的方式
class Person {
  // 使用 static 关键字,可以定义静态属性
  // 所谓的静态属性,就是 可以直接通过 类名, 直接访问的属性
  // 实例属性: 只能通过类的实例,来访问的属性,叫做实例属性
  static info = { name: 'zs', age: 20 }
}

// 访问 Person 类身上的  info 静态属性
console.log(Person.info)

会报错

webpack学习一_第26张图片

因为在 webpack 中,默认只能处理 一部分 ES6 的新语法,一些更高级的ES6语法或者 ES7 语法,webpack 是处理不了的;这时候,就需要 借助于第三方的 loader,来帮助webpack 处理这些高级的语法,当第三方loader 把 高级语法转为 低级的语法之后,会把结果交给 webpack 去打包到 bundle.js 中

而通过 Babel ,可以帮我们将 高级的语法转换为 低级的语法

  • 在 webpack 中,可以运行如下两套 命令,安装两套包,去安装 Babel 相关的loader功能:

第一套包(负责转换,但是不知道高级语法到低级语法的对应关系): cnpm i babel-core [email protected] babel-plugin-transform-runtime -D

webpack学习一_第27张图片

第二套包(语法插件,): cnpm i babel-preset-env babel-preset-stage-0 -D

webpack学习一_第28张图片

  • 打开 webpack 的配置文件,在 module 节点下的 rules 数组中,添加一个 新的 匹配规则:

{ test:/\.js$/, use: 'babel-loader', exclude:/node_modules/ }

注意: 在配置 babel 的 loader规则的时候,必须 把 node_modules 目录,通过 exclude 选项排除掉:

如果 不排除 node_modules, 则Babel 会把 node_modules 中所有的 第三方 JS 文件,都打包编译,这样,会非常消耗CPU,同时,打包速度非常慢;

即使最终,Babel 把 所有 node_modules 中的JS转换完毕了,但是,项目也会无法正常运行

  • 在项目的 根目录中,新建一个 叫做 .babelrc 的Babel 配置文件,这个配置文件,属于JSON格式,所以,在写 .babelrc 配置的时候,必须符合JSON语法规范: 不能写注释,字符串必须用双引号

在 .babelrc 写如下的配置: 可以把 preset 翻译成 【语法】 的意思

{

"presets": ["env", "stage-0"],

"plugins": ["transform-runtime"]

}

  • 了解: 目前,我们安装的 babel-preset-env, 是比较新的ES语法, 之前, 我们安装的是 babel-preset-es2015, 现在,出了一个更新的 语法插件,叫做 babel-preset-env ,它包含了 所有的 和 es***相关的语法

但是在此过程中还是产生了Cannot find module '@babel/core'这个错误,参考https://www.cnblogs.com/soyxiaobi/p/9554565.html

总结:以上安装的所有的包

cnpm install --save-dev webpack-cli
cnpm install --save-dev webpack
cnpm install webpack-dev-server
cnpm install webpack-dev-server --save-dev
cnpm install html-webpack-plugin --save-dev
cnpm install style-loader css-loader --save-dev
cnpm install sass-loader node-sass --save-dev
cnpm install url-loader file-loader --save-dev
cnpm i babel-core [email protected] babel-plugin-transform-runtime --save-dev
cnpm i babel-preset-env babel-preset-stage-0 --save-dev

 

你可能感兴趣的:(webpack)