webpack基础知识

150 阅读5分钟

一 webpack是模块打包工具

【webpack官方文档查看:webpack模块的概念模块的方法和变量

1. 面向过程开发

随着业务代码增加,后期维护困难。可能要在几千行代码里去找错改错。

cd Desktop
touch index.html // ! 初始化html文档
touch index.js

点击查看【juejin】

2. 面向对象开发

cd Desktop
mkdir lesson
cd lesson
touch index.html // ! 初始化html文档
touch index.js
touch header.js
touch sidebar.js
touch content.js

点击查看【juejin】

// ES Module 模块引入方式
// 但是原生浏览器不识别import语句。
// 这个时候webpack就登场了!webpack翻译以下语句,浏览器就识别了。
import Header from './header.js'
import Sidebar from './sidebar'
import Content from './content'

var dom = document.getElementById('root')

new Header();
new Sidebar();
new Content();

当使用面向对象开发时,如上面使用到了export / import语法(ES Module 模块引入方式),但是原生浏览器不识别import语句。这个时候webpack就登场了!webpack翻译之后语句之后浏览器就识别了。下面开始安装并使用webpack。

3. 安装Node和NPM

webpack是基于node开发的模块打包工具,所以它本质上是由node实现的。提升webpack打包速度的2个重要的方法: 1 node版本最新 2 webpack版本最新。

(1) Mac下卸载node

// 一.在终端依次输入以下命令
sudo npm uninstall npm -g

sudo rm -rf /usr/local/lib/node /usr/local/lib/node_modules /var/db/receipts/org.nodejs.*

sudo rm -rf /usr/local/include/node /Users/$USER/.npm

sudo rm /usr/local/bin/node

sudo rm /usr/local/share/man/man1/node.1

sudo rm /usr/local/lib/dtrace/node.d

// 二.验证是否成功
// 如果上述代码你已经按照顺序去执行一遍了,那我们就需要来验证一下我们有没有删除成功。
// 如果出现一下结果说明我们就是删除成功了。

node -v  //not found
npm -v //not found

// 三.接下来就可以去官网下载我们需要的版本
https://nodejs.org/en/

(2) Mac下安装node

// (1)安装node版本管理模块n
sudo npm install n -g

//下边步骤请根据自己需要选择
//(2)安装稳定版
sudo n stable

//(3)安装最新版
sudo n latest

//(4) 版本降级/升级
sudo n 版本号 //例如:sudo n 10.13.0

4. webpack的环境搭建

(1) 创建package.json

// 依次执行如下命令 生成一个package.json文件
mkdir webpack-demo
cd webpack-demo
npm init // npm init -y

// 手动配置package.json ("private": true,)
 "name": "webpack-demo",
 "version": "1.0.0",
 "description": "",
 "private": true,
 // "main": "index.js", // 删除是因为项目是我们自己使用,没必要向外暴露一个js文件

(2) 安装webpack和webpack-cli

// 注意:webpack和webpack-dev-server有版本兼容性的要求
// webpack 3.x 要使用 webpack-dev-server 2.x
// webpack 4.x 要使用 webpack-dev-server 3.x
// 全局安装指定版本的webpack-dev-server(局部安装去掉-g)
npm install webpack-dev-server@3.11.3 -g

a. 全局安装(不推荐)
// 卸载
npm uninstall webpack webpack-cli -g

// 一起安装
npm install webpack webpack-cli -g
// 或者分别单独安装
npm install webpack --save
npm install webpack-cli --save-dev


// 全局安装指定版本的webpack
npm install webpack@4.25.1 -g // npm install webpack --save

// 全局安装指定版本的webpack-cli
npm install webpack-cli@3.1.2 -g // npm install webpack-cli --save-dev

// 查看版本号 -- 全局查找
webpack -v

b. 在项目内安装webpack(推荐)
// 卸载
npm uninstall webpack webpack-cli --save-dev
// 安装
npm install webpack webpack-cli --save-dev // 二者等价
npm install webpack webpack-cli -D // 二者等价

// 安装指定版本的webpack到package.json文件中
npm info webpack // 查看webpack的版本号信息,确认是否存在4.26.0版本
npm install webpack@4.26.0 webpack-cli@3.1.2 --save-dev

// 查看版本号 -- 当前文件夹的node_modules下查找
npx webpack -v
npx webpack-cli -v

安装完成之后在package.json文件里可以看到对应的版本信息,如下。
aceab394104e4cbbb63b80b493f88824_tplv-k3u1fbpfcp-watermark.jpeg
然后执行以下命令打包:

npx webpack index.js // 用webpack翻译index.js文件,以便识别important语法。

执行完npx webpack index.js之后,lesson文件夹下会生成dist/main.js文件,这个才是浏览器能识别的js文件。
2.jpg
至此,index.html就可以在浏览器运行了。所以webpack就是一个翻译器吗?答案是否定的。那webpack到底是什么呢?

5. webpack是模块打包工具

在上面的例子中,webpack其实并不能翻译其他的语法(只认识import),它的功能是把Header、Sidebar、Content三个模块打包到了一起,生成一个最终的js文件。所以是一个模块打包工具。我们在写JS的时候,不仅有ES Module这样的语法,还有CommonJS(Nodeh中最常用的模块引入规范)这样的语法,另外还有CMD、AMD这样的规范。webpack都能识别。

// 引入方式
// ES Module
import Header from './header.js'
import Sidebar from './sidebar'
import Content from './content'

// CommonJS
var Header = require('./header.js')
var Sidebar = require('./sidebar.js')
var Content = require('./content.js')

// 导出方式
// ES Module
// export default Header;
// export default Sidebar;
// export default Content;

// CommonJS
module.exports = Header
module.exports = Sidebar
module.exports = Content

webpack刚推出的时候仅仅是js的模块打包工具。随着webpack的发展,现在可以打包任何形式的模块文件。比如.css文件、.jpg/.png等格式的图片文件,等等其他任何形式的模块文件。

二 webpack.config.js配置文件

【webpack官方文档查看:入口和上下文(entry-context)输出(output)webpack的安装和起步

1. entry和output配置

在默认webpack的配置下,我们使用npx webpack index.js打包js入口文件。

cd Desktop // 桌面
mkdir lesson // 在桌面创建lesson文件夹
cd lesson
touch index.html // 创建index.html文件 (! 初始化html文档 )
touch index.js // 创建index.js
touch header.js // 创建header.js
touch sidebar.js // 创建sidebar.js
touch content.js // 创建sidebar.js

npm init // 创建package.json文件 默认一路回车
npm install webpack@4.26.0 webpack-cli@3.1.2 -D // 安装webpack和webpack-cli
npx webpack index.js // 用webpack打包index.js

有时候我们需要自定义配置文件该怎么办呢?如下:在lesson文件夹下新建webpack.config.js文件,并做如下配置。然后执行npx webpack打包就可以了。

// 当执行npx webpack时,webpack内部会寻找webpack.config.js文件
// 并根据entry和output的配置选择入口js文件和打包之后输出的路径和文件名。
npx webpack // 当在webpack.config.js文件里声明了entry和output之后使用

在默认情况下创建的webpack配置文件名称是webpack.config.js,同时我们也可以自定义文件名。比如webpackconfig.js,那我们打包的时候执行如下命令就可以了。

npx webpack --config webpackconfig.js // 以webpackconfig.js为配置文件进行打包

(1)单entry、单output打包

a.jpg

(2)多entry、多output打包

b1.jpg
b2.jpg

2. 项目目录的优化及npm run bundle的实现

在package.json文件的script对象里,配置bundle快捷命令。这样以后用webpack打包模块的时候就可以执行如下命令了

npm run bundle // 二者等价
npx webpack // 二者等价

// 注意
// webpack会优先在当前项目下的node_modules里去查找webpack,如果没有找到才会到全局去查找。
script: { // 在package.json里script对象作如下配置
  bundle: 'webpack' // 这里是webpack,而不是npx webpack。
}

package.json的配置
c.jpg
webpack.config.js的mode和entry配置详解
d.jpg

3. webpack的三种运行方式

// 1 全局安装
webpack index.js
// 2 局部安装
npx webpack index.js
// 3 npm scripts
npm run bundle // package.json文件配置

我们在安装webpack的时候,同时还安装了webpack-cli,它的作用是使得我们在命令行里可以正常使用webpack的命令。

三 webpack之Loader

1. 什么是Loader

webpack默认是只能识别并打包js模块,如果想打包css、jpg等其他模块,需要使用Loader。
所以Loader是一个打包方案,它知道对于一个特定的文件,webpack应该如何的进行打包。webpack可以借助于Loader打包对应的资源。

2. 使用Loader打包静态资源

(1)file-loader和url-loader的使用和区别

url-loader可以实现file-loader的一切功能,不一样的是它会把图片转化为base64的字符串直接放到bundle.js里。好处是不用单独请求图片地址少了一次http请求,不好的地方是导致bundle.js文件变大。建议:图片很小时,可以转化为base64放到js文件,过大时,还是以图片的格式单独存放。可以使用limit配置实现。
【webpack官方文档查看:占位符placeholderfile-loader文档 url-loader文档

loader的安装
npm install file-loader -D
npm install url-loader -D

// 打包不同的模块module,使用相应的Loader
module: {
    rules: [{
      // test: /\.jpg$/, // 文件后缀.jpg 识别到jpg格式的图片时,借助file-loader打包,移动到dist目录下
      test: /\.(jpg|png|gif)$/,
      use: {
        loader: 'file-loader',
        options: {
          // [name]_[hash].[ext]  这个被称为placeholder 占位符
          name: '[name]_[hash].[ext]', // 打包生成的文件名称和后缀跟原始文件保持一致
          outputPath: 'images/'
        }
      }
    },{
      test: /\.(jpg|png|gif)$/,
      use: {
        loader: 'url-loader',
        options: {
          name: '[name]_[hash].[ext]',
          outputPath: 'images/',
          limit: 2048 // 2048个字节 2kb 小于2kb转化为base64,大于2kb会以图片格式单独存放
        }
      }
    }]
  },

x2.jpg

(2)打包样式

【webpack官方文档查看:css、iconfont的打包css-loadersass-loaderstyle-loaderpostcss-loader
x4.jpg

四 webpack之plugins-让打包更便捷

1. 什么是plugin

在webpack运行到某个时刻的时候帮你做一些事情(类似于vue的声明周期函数)。
【webpack官方文档查看:管理输出-设置 HtmlWebpackPluginhtml-webpack-plugin

(1)HtmlWebpackPlugin

HtmlWebpackPlugin会在打包结束后,自动生成一个html文件,并把打包生成的js自动引入到这个html文件中。

npm install --save-dev html-webpack-plugin

(2)clean-webpack-plugin

作用是打包前先删除之前的dist目录

npm install clean-webpack-plugin@1.0.0 -D

(3)使用

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');

module.exports = {
  mode: 'development',
	entry: {
		main: './src/index.js'
	},
  plugins: [
		new HtmlWebpackPlugin({
			template: 'src/index.html'
		}),
		new CleanWebpackPlugin(['dist'])
  ],
	output: {
		filename: 'bundle.js',
		path: path.resolve(__dirname, 'dist')
	}
};

五 webpack之SourceMap

1. sourceMap的作用

它是一个映射关系,假如说打包后的dist目录下的main.js文件中第96行出错,实际上对应的是打包前的src目录下index.js中的第1行出错了,sourceMap做了一个映射,便于开发过程中排查问题。devtool文档
s1.jpg
source-map 代码在第几行第几个字符出错,并生成对应的.map文件(打包后出错的地方跟源文件出错的地方建立映射关系的文件)
如果不使用sourceMap,只知道打包代码出错了,但不知道源代码的位置。

  • mode: development
    development环境下最佳推荐: cheap-module-eval-source-map。提示的错误比较全,同时打包速度比较快。
  • mode: production
    production环境下最佳推荐: cheap-module-source-map(一般不用devtool)

2. 各个方式的区别

(1) source-map

1 生成.map的文件
2 代码在第几行第几个字符出错
3 将打包后的js代码出错的地方跟业务代码建立映射关系
4 耗费性能

(2) inline-source-map(inline的作用)

1 不生成单独的.map文件(内容被以base64位的格式存放在生成的js文件里)
2 代码在第几行第几个字符出错
3 将打包后的js代码出错的地方跟业务代码建立映射关系
4 耗费性能

(3) cheap-inline-source-map(cheap的作用)

1 不生成单独的.map文件(内容被以base64位的格式存放在生成的js文件里)
2 代码在第几行出错
3 只映射业务代码和打包后的js代码,不映射第三方代码和打包后的js代码
4 提升打包性能

(4) cheap-module-inline-source-map(module)

1 不仅映射业务代码和打包后的js代码,还映射loader、第三方模块的代码和打包后的js代码

(5) eval

1 打包速度最快的方式,执行效率最快,性能最好的方式
2 但是如果比较复杂的代码,提示的可能并不全面。
s2.jpg

六 webpack之WebpackDevServer-提升开发效率

1. webpack-dev-server的安装

npm install webpack-dev-server@3.1.10 -D

webpack-dev-server运行的时候并不会生成dist文件夹。而是把生成的文件保存在内存中,从而提升打包速度。
d1.jpg

七 webpack之Hot Module Replacement模块热更新

webpack-dev-server运行的时候并不会生成dist文件夹。而是把生成的文件保存在内存中,从而提升打包速度。

1. 开启Hot Module Replacement

【webpack官方文档查看:HMR模块热替换
页面代码修改不会重新刷新整个页面,只刷新代码修改的部分。
h1.jpg

八 webpack之Tree Shaking

1. Tree Shaking的作用

只打包需要用到的模块,用不到的模块不作打包。

export const add (a, b) {
    console.log(a + b)
}

export const minus (a, b) {
    console.log(a - b)
}
import { add } from './utils.js'
add(1,2)

Tree Shaking只支持ES Module的引入方式。不支持CommonJS。
原因:
1 import这种ES Module的引入方式底层是静态的引入方式
2 CommonJS是一种动态的引入方式。

// webpack.config.js
optimization: { // development环境下.production环境下不需要
  usedExports: true
}

// package.json
{
  "name": "lesson",
  "sideEffects": false, // 没有不需要tree shaking的文件
  "scripts": {}
}