什么是webpack
官方概念
webpack 是现代 js 应用程序的静态模块打包器,当 webpack 处理应用程序时,它会递归的构建一个依赖关系图,其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个bundle。
个人理解
webpack可以看做是模块打包机,主要做的事情是,分析项目结构,找到 js 模块以及其他的一些浏览器不能直接运行的扩展语言(scss ts等)将其转换和打包为合适的格式供浏览器使用
模块和打包的由来
模块
曾经的前端开发方式,js文件是通过 script 标签静态引入,js 文件之间没有强依赖关系,如果文件 1 要用到文件 2 的某些方法或变量,必须将文件 1 放在文件 2 的后面加载,随着项目的增大, js 文件之间的依赖关系越来越复杂,维度难度也越来越高,从而引入模块的概念让 js 文件之间可以相互引用,例如模块 1 要使用模块 2 的功能,只需要在该模块 1 中明确引用模块 2 就可以,不用担心它们的引用顺序,因此基于这种理念, 有了 Commonjs、AMD 规范被创造出来,有了 require.js system.js 这样的前端模块加载工具和 node 模块系统以及现在流行的 es6 module
打包
模块的引入是为了解决文件之间依赖引用的问题,打包是为了解决文件过多问题,当项目规模增大,模块的数量数以千计,浏览器加载如此多的文件,页面的加载速度会受到影响,而 bundle 可以把多个关联的文件打包到一起从而减少文件的数量提高网页加载性能
模块化打包工具的由来
1、解决开发阶段代码在实际生产运行环境中兼容性问题
2、将零散的模块文件打包到统一的文件中,避免由于模块文件过多造成频繁的网络请求
3、实现所有前端资源的模块化,不仅仅是 js 模块化
webpack和grunt gulp的区别
grunt 和 gulp 的工作方式是:在一个配置文件中,指明对某些文件进行类似编译、组合、压缩等任务的具体步骤,使用工具之后可自动替你完成这些任务
webpack工作方式是:把项目当做一个整体,通过给定的主文件,将从这个主文件找到项目的所有依赖文件,使用 loaders处理,最后打包为一个或多个浏览器可以识别的 Js 文件
核心概念
模块(module)
对于 webpack ,模块不仅仅是 js 模块,它包括了任何类型的源文件,不管是图片、字体、json文件都是一个个模块,webpack支持以下方式引用模块:
1、es5 import 方法
2、CommonJs require()方法
3、AMD define和 require语法
4、css/sass/less文件中的 @import 语法
5、url(...) 和 <img src=...>中的图片路径
依赖关系图
是 webpack 根据每个模块之间的依赖关系生成的一张内部逻辑图,根据这张依赖图,webpack能按图把所需要的模块打包成一个 bundle 文件
入口(entry)
入口起点指示 webpack 应该使用哪个模块来作为构建其内部依赖图的开始,进入入口起点后,webpack会找出有哪些模块和库是入口起点(直接或间接)依赖的
1、单入口
const config = {
entry: 'index.js'
}
2、多入口
const config = {
pageOne: 'index1.js',
pageTwo: 'index2.js'
}
出口(output)
output属性告诉 webpack在哪里输出它所创建的 bundles,以及如何命名这些文件,默认值为 ./dist 基本上,整个应用程序结构,都会被编译到你指定的输出路径文件夹中。
用法:
在 webpack 中配置 output属性的最低要求是,将它的值设置为一个对象,包括以下两点
filename: 输出文件的文件名
path: 目标输出目录(为绝对路径)
单个入口起点
const config = {
output: {
filename: 'bundle.js',
path:'/home/assets'
}
}
** 多个入口起点 **
const config = {
entry: {
app: './src/app.js',
search: './src/search.js'
},
output: {
filename: '[name].js',
path: __dirname + '/dist'
},
}
补充说明 webpack打包中 path.resolve和__dirname的含义
1、path 是 node中的一个核心模块。path.resolve将路径或路径的片段解析为绝对路径,原则是给定的路径序列会从右到左处理,后面的每个 path 会被追加到前面,直到构造出绝对路径
总结
参数从右向前,若字符以/ 开头,返回值不会拼接到前面的路径;若以 ../ 开头,返回值拼接前面的路径,但是不包含前面路径的最后一层路径;若以 ./开头或者没有符号,则拼接前面的路径
举例如下:
当前的工作路径为/workspace/demo
console.log(path.resolve()) // returns /workspace/demo
console.log(path.resolve('')) // returns /workspace/demo
console.log(path.resolve(__dirname)) // returns /workspace/demo
console.log(path.resolve('/img/books', '/net')) // returns '/net'
console.log(path.resolve('img/books', '/net')) // returns '/net'
console.log(path.resolve('img/books', './net')) // returns '/workspace/demo/img/books/net'
console.log(path.resolve('/img/books', './net')) // returns '/img/books/net'
console.log(path.resolve('/img/books', 'net')) // returns '/img/books/net'
console.log(path.resolve('/img/books', '../net')) // returns '/img/net'
console.log(path.resolve('src','/img/books', '../net')) // returns '/img/net'
console.log(path.resolve('src','./img/books', '../net')) // returns '/workspace/demo/src/img/net'
console.log(path.resolve('src','img/books', '../net')) // returns '/workspace/demo/src/img/net'
2、__dirname获得当前文件所在目录的完整路径名
模式
通过选择 development 或 production 之中的一个,来设置 mode 参数,可以启用相应模式下的 webpack 内置的优化
1、production: 生产模式,会启用内置的插件对打包的代码进行压缩优化等操作
2、development: 开发模式,更注重打包效率,不对代码进行压缩
3、none: 纯打包模式,以原始的状态打包代码
module.exports = {
mode: 'production'
}
loader
loader 让 webpack 能够处理那些非 js 文件(webpack 自身只理解 Js)。loader可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后就可以利用 webpack的打包能力,对它们进行处理
使用方式
1、test 属性:用于标识出应该被对应的 loader 进行转换某个或某些文件
2、use属性:表示进行转换时,应该使用哪个 loader
const path = require('path');
const config = {
module: {
rules: [
{
test: /\.txt$/, use: 'raw-loader'
}
]
}
}
实现过程:此段代码告诉 webpack 解析器,当遇到 repuire import语句中被解析为 .txt的路径时,对它打包之前,先使用 raw-loader转换一下
插件(plugins)
plugin 主要是用来扩展 webpack 功能的,通过在构建流程里注入钩子实现,给 webpack带来了很大的灵活性
使用方法
1、在 webpack 的配置中,向 plugins 属性传入 new 实例
基本使用方式
(1)引入插件
const HtmlWebpackPlugin = require('html-webpack-plugin');
(2)配置插件
plugins: [
new HtmlWebpackPlugin()
]
配置
webpack 的配置文件,是导出一个对象的 js 文件,此对象,由 webpack 根据对象定义的属性进行解析;
webpack 配置是标准的 Node.js CommonJS 模块,可以做到以下事情:
1)通过 require(...) 导入其他文件
2)通过 require(...) 使用 npm 的工具函数
3)使用 js 的控制流表达式,例如 ?:
4)对常用值使用常量或变量
5)编写并执行函数来生成部分配置
基本配置
const path = require('path');
module.exports = {
mode: 'development',
entry: './foo.js',
output: {
path: path.resolve(__dirname,'dist'),
filename: 'foo.bundle.js'
}
}
模块
模块
开发者将程序分解成离散功能模块,称之为模块;
模块特点
每个模块具有比完整程序更小的接触面,使得校验、调试、测试轻而易举。精心编写的模块提供了可靠的抽象和封装界限,使得应用程序中每个模块都具有条理清楚的设计和明确的目的
什么是webpack模块
- es5 的 import 语句
2)CommonJs 的 require 语句
3)AMD 的 define 和 require 语句 - css/sass/less 文件中的 @import 语句
5)样式 url(...)或HTML文件<img src=‘...’>中的图片链接
模块解析
resolver 是一个库,用于帮助找到模块的绝对路径,一个模块可以作为另一个模块的依赖模块,被引用
webpack解析规则
主要解析三种文件路径
1)绝对路径
import "/home/me/file"
- 相对路径
import "../src/file"
- 模块路径
import "module"
模块将在 resolve.modules中指定的所有目录内搜索,可以替换初始模块路径,替换初始路径可以通过 resolve.alias 创建一个别名
module.exports = {
resolve: {
alias: {
'vue': 'vue/dist/vue.js'
}
}
}
manifest
Runtime
runtime 以及伴随的 manifest 数据,主要是指:在浏览器运行时,webpack用来连接模块化的应用程序的所有代码
Manifest
当编译器开始执行、解析和映射应用程序时,会保留所有模块的详细要点。
构建目标(targets)
因为服务器和浏览器代码都可以用 js 编写,所以 webpack 提供了多种构建目标,配置如下:
module.exports = {
target: 'node'
}