-
webpack是什么?
-
为什么要用webpack?
-
如何使用webpack?
-
常见问题及解决办法。
答案:
1:webpack是一个现代js应用程序得静态模块打包器。当webpack处理应用程序时,会递归得构建一个依赖关系图,包含应用程序需要的每个模块,然后将这些模块打包成一个或多个包。在webpack中一切皆模块,通过loader转换文件,通过plugin注入插件,最后输出由多个模块组成的文件。 经过webpack的处理,最终会输出浏览器能使用的静态资源。
2:webpack是一个前端自动化构建工具,简单得说我们为了将一些在开发中比较繁琐得工作,比如代码压缩打包,交给工具来做,提高开发效率。并且可以保证开发过程中开发的统一性。
webpack的优点:a,专注于处理模块化的项目;b,可通过plugin扩展,完整好用灵活;c,使用场景不局限于web开发; d,社区活跃,紧跟时代发展的新特性;e,良好的开发体验。
缺点:只能用于采用模块化开发的项目。
3,我们将所有需要工具来做的事情,利用一个配置文件进行配置管理。在webpack4.0开始可以先不引入一个配置文件,在使用之前需要先了解几个核心概念,入口(entry)、输出(output)、loader、插件(plugins)。
4:常见问题:在安装webpack之后,执行命令 提示 webpack:command not found
原因一: webpack 没有安装成功
原因二:环境变量问题
webpack打包原理:
webpack只是一个打包模块的机制,只是把依赖的模块转化成可以代表这些包的静态文件。并不是什么commonjs或者amd之类的模块化规范。webpack就是识别你的 入口文件。识别你的模块依赖,来打包你的代码。至于你的代码使用的是commonjs还是amd或者es6的import。webpack都会对其进行分析。来获取代码的依赖。webpack做的就是分析代码。转换代码,编译代码,输出代码。webpack本身是一个node的模块,所以webpack.config.js是以commonjs形式书写的(node中的模块化是commonjs规范的) webpack中每个模块有一个唯一的id,是从0开始递增的。整个打包后的bundle.js是一个匿名函数自执行。参数则为一个数组。数组的每一项都为个function。function的内容则为每个模块的内容,并按照require的顺序排列。
开始安装学习 webpack
注意:webpack4基于node版本6.11.5以上
安装:
安装前置环境:nonde(自带npm包管理工具) git
1,全局安装webpack 命令 npm install webpack -g
这里我新建了一个文件夹,已经在文件夹中运行git
2 执行命令 npm init 初始化项目 这样我我们就可以得到一个package.json文件
3,安装webpack到本项目下使用 命令 npm install webpack webpack-cli -D -D为--save-dev的缩写,是指安装模块
并保存到package.json的devDependencies目录下,记录当前项目开发过程中所依赖的包
此时我们输入 命令 webpack 这时候回出现错误与警告
原因为在webpack更新到4之后,会有默认的入口与出口,找到当前目录下的src文件夹中的index.js作为默认的入口打包文件。 在当前文件夹下新建src文件夹,在文件夹下新建index.js文件,再次打包。会将index.js打包到dist文件夹下的main.js。
将webpack安装到全局后,我们可以在任何地方共用一个webpack可执行文件,推荐本地项目局部安装webpack,防止不同的项目因为依赖不同的版本webpack而导致冲突。
使用:
1,基本使用
利用commonJs模块化规范封装模块,并通过require导出。我们需要 新建 webpack.config.js 配置文件,在这个配置文件中我们来配置webpack打包处理文件的规定。
entery 入口:模块的入口,多个入口可以为对象的形式。
output输出:filename为输出的文件名,path为经过打包处理后输出的文件路径。
webpack是一个打包模块化js的工具,从main.js出发,识别出源码中的模块化导入语句,递归的找出入口文件的所有依赖,将入口和其所有依赖打包到一个单独的文件中,webpack内置对Es6,commonJs,AMD模块化语句的支持。
var path = require('path')
module.exports = {
entry:'./src/main.js',
output:{
filename:'bundle.js',
path:path.resolve(__dirname,'./dist')
}
}
2,使用loader
在文件中引入css样式文件,webpack将一切均看成模块,css同样也是。
loader可以看作具有文件转化功能的翻译员,数组配置了一组规则,告诉webpack遇到哪些文件时使用什么
loader去加载和转换。
a,use属性的值需要是一个由loader名称组成的数组,loader的执行顺序是由后到前的。
b,每个loader都可以通过URL querystring 的方式传入参数,
在使用loader之前需要先把loader下载下来,(输入命令 npm i style-loader css-loader -D )
//应用loader(装载机)
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
]
}
};
将css的内容用js里的字符串存储起来,在网页执行js时通过DOM操作,动态的向html head标签中插入style标
签,同样也可以单独输出css文件,可以通过插件机制来实现。
3,使用插件【Plugins】
loader被用于转换某些类型的模块,而插件则可以用于执行范围更广的任务。插件包括从打包优化和压缩,一直到重新定义环境中的变量。用来扩展webpack功能,通过在构建流程里注入钩子实现。为webpack带来很大的灵活性。
例如:通过插件单独提取打包css文件,通过require引入插件模块,再调用。
[contentHash:8]代表根据文件内容算出的8位Hash值。(这里就放整体的配置文件代码)
var path = require("path");
var MiniTextPlugin = require('mini-text-plugin')
module.exports = {
entry: "./src/main.js",
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "./dist")
},
//当前模式,开发development(不压缩)or上线production(压缩的)
mode: "development",
//开启服务器。修改打开基础路径和端口号
devServer: {
contentBase: "dist",
port: 999
},
//应用loader(装载机)
module: {
rules: [
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
}
]
},
plugins:[
new MiniTextPlugin({
//从.js文件中提取来的.css文件名称
filename:'[name]_[contenthash:8].css'
})
]
};
4,使用DevServer
在实际开发中还会遇到,在实际开发中具有以下需求;
- 提供http服务而不是使用本地文件预览。
- 监听文件变化并自动刷新网页,做到实时预览。
- 支持source Map,方便调试。
利用开发工具DevServer可以实现,DevServer会开启http服务器用于服务网页请求。同时帮助启动webpack,接收webpack发出的文件变更信号,通过WebSocket协议自动刷新网页做到实时预览。
1,下载webpack-dev-server
2.运行webpack-sev-server (如果运行失败。可以全局安装)
//当前模式,开发development(不压缩)or上线production(压缩的)
mode:'development',
//开启服务器。修改打开基础路径和端口号
devServer:{
contentBase:'dist',
port:999
}
DevServer启动的HTTP服务器默认监听在8080端口,可以通过配置文件进行修改,DevServer启动后会一直驻留
在后台保持运行,访问这个网址可以获取项目根目录下的index.html。可以用浏览打开网址。
5,实时预览
webpack在启动时也可以通过webpack --watch开启监听模式。
通过DevServer启动的webpack会开启监听模式,当文件内容变化时重新进行构建,然后通知DevServer。DevServer会让webpack在构建出的js代码里注入一个代理客户端来控制网页。网页和DevServer之间通过WebSocket协议通信,方便DevServer主动向客户端发送命令。
DevServer在收到来自webpack的文件变化通知时,通过注入的客户端控制网页刷新。如果修改引入模块的html文件就不会实现自动刷新。
原因是webpack在启动时会以配置里的entry为入口去递归解析出入口所依赖的文件,只有entry本身和依赖的文件才会被webpack添加到
监听列表中 。
6,模块热替换
开启监听通过重新刷新整个页面来实现实时预览,DevServer中还有一种刷新技术 --- 模块热替换。
可以做到在不刷新整个网页的情况下,通过将已更新的模块替换旧模块,再重新执行一次实现实时预览。更快更好的开发体验。
通过命令webpack-dev-server --hot实现。
核心概念
- entry:入口,webpack执行构建的第一步,可抽象成输入。
- Module:模块,在webpack里一切皆模块,一个模块对应一个文件。webpack会从配置的Entry开始递归找出所
- 有依赖的模块。
- chunk:代码块,一个chunk由多个模块组成,用于代码的合并与分割。
- loader:模块转化器,用于将模块的原内容按照需求转换成新内容 。loader 让 webpack 能够去处理那些非
- JavaScript 文件(webpack 自身只理解 JavaScript)。
- Plugin:扩展插件,在webpack构建流程中的特定时机注入扩展逻辑,用来改变构建结果或做我们想要的事
- 情。
- Output:输出结果,在webpack经过一系列处理并得出最终想要的代码后输出的结果。
配置
配置webpack 的方式:
- 通过一个js文件描述配置,例如webpack.config.js
- 执行webpack可执行文件时通过命令行参数传入,例如下图通过命令行设置当前环境变量
同时这两种方式可以互相搭配,例如执行webpack时通过命令webpack--config webpack-dev.config.js指定配置文件,再去webpack-dev.config.js文件里描述部分配置。
Entry是配置文件的入口,可抽象为输入,webpack执行构建的第一步将从入口开始搜寻及递归解析出所有的入口依赖模块。Entry必填,不填会出错。
context webpack在寻找相对路径的文件时会以context为根目录,context默认为执行启动webpack时所在的当前工作目录。
3, Entry类型
字符串:对应单个文件入口
对象和数组:对应多个文件如果
4, Chunk
webpack会为每个生成的chunk取一个名称,名称与Entry配置有关。如果entry是一个sring或array,就只会生
成一个Chunk,名称为main
Entry是一个obj,就会出现多个Chunk,这时chunk名称是obj中的键的名称。
5, output
Output配置如何输出最终想要的代码。是一个object类型,里面包含一系列的配置项。
output.filename配置文件输出的名称,为string类型。如果只有一个输出文件,可以写成静态不变的。有多个
Chunk要输出时,需要借助模板和变量。[name].js中[name]代表使用内置的name变量去替换[name]。
output.path配置输出文件存放本地的目录,必须是string类型的绝对路径,通常通过Node.js的path模块去获
取绝对路径。
Webpack流程概括
初始化-->编译-->输出
webpack的运行流程是一个串行的过程,从启动到结束会依次执行以下流程。
初始化参数:从配置文件和shell语句中读取与合并参数,得出最终参数。
开始编译:用上一步得到的参数初始化Compiler(编译)对象,加载所有配置的插件,通过执行对象的run方法开始执行编译。
确定入口 :根据配置中的entry找出所有入口文件。
编译模块 :从入口文件出发,调用所有配置的loader对模块进行翻译,再找出该模块依赖的模块,再递归本步骤直到所有入口依赖的文
件都经过本步骤的处理。
完成模块编译:在经过第四步使用loader翻译完成所有模块后,得到了每个模块被翻译后的最终内容及他们之间得关系。
输出资源:根据入口和模块之间的依赖关系,组装成一个个包含多个模块的Chunk,再将每个Chunk转换成一个单独的文件加入输出列表
中,这是可以修改输出内容的最后机会。
输出完成:在确定好输出内容后,根据配置确定输出的路径和文件名。将文件的内容写入系统中。
关于全局安装和本地安装问题:
因为我们需要的包可能有十个,他们之间相互依赖的,如果我们使用全局包,那么每次包的升级、更新等就会影响你的多个项目,那么依赖关系就会被破坏,所以使用本地安装有利于不同项目之间的独立性。