安装
webpack 是一个使用Node.js实现的一个模块化代码打包工具。所以,需要先安装webpack,安装之前需要搭建好Node.js环境
npm install -D webpack webpack-cli
注:不推荐全局安装
webpack-cli:提供webpack命令、工具
使用
// 初始化项目 生成package.json文件
npm init -y
./node_modules/.bin/webpack
// 查看版本
./node_modules/.bin/webpack -v
也可以编辑package.json的scripts来简化输入
// package.json
{
...
"scripts": {
"start": "webpack" // scripts中可以定位到./node_modules/.bin 目录下
}
}
scripts 中使用test、start、restart、stop命令时,可以在调用的时候省略run,直接npm start
或者使用更方便的方式,npx可以定位到./node_modules/.bin 目录下
npx webpack
// npm5.2+增加,如果没有,可以使用npm i -g npx 来安装
打包模块
入口文件
入口文件就是我们项目中加载的第一个文件,比如main.js文件,其他文件都是通过import等方式引入的,webpack会从我们指定的入口文件开始分析所有需要依赖的文件,然后打包成一个完整的文件。
打包命令
webpack ./js/index.js
上面的命令会使用webpack默认的一些配置对模块文件进行打包,并把打包后的文件输出到默认创建的./dist目录下,打包后的文件名默认为main.js。
模块文件打包以后,就可以在不支持es6模块语法的浏览器环境下引入使用了。
打包文件分析
- 把分散的模块文件打包到一个文件中,不需要外部引入了
- 内置了一个小型模块加载器(类似requireJS),实现了打包后的代码隔离与引用
以上就是webpack最基础的使用基本原理。
打包配置
虽然,可以直接通过命令来打包,但还是推荐创建一个webpack.config.js的配置文件来实现。webpack命令在运行的时候,默认会读取运行命令所在的目录的webpack.config.js文件,通常我们会在项目的根目录下运行命令和创建配置文件。也可以使用--config选项来指定配置文件路径:
webpack --config ./configs/webpack.config.js
配置文件
导出的就是一个对象,这个对象就是webpack命令执行过程中使用到的配置
module.exports = {
... // 配置项
}
核心配置
编译模式( mode)
module.exports = {
mode: 'development' // 可以配置为production | development | none
}
编译入口文件(entry)
指定打包入口文件,有三种不同的形式:string | object | array
// 一对一:一个入口文件、一个打包文件
module.exports = {
entry: './src/index.js'
}
// 多对一:多个入口文件,一个打包文件
module.exports = {
entry: [
'./src/index.js',
'./src/main.js'
]
}
// 多对多:多个入口文件,多个打包文件
module.exports = {
entry: {
main: './src/main.js',
index: './src/index.js'
}
}
编译出口配置(output)
打包后的文件位置
import path = require('path');
module.exports = {
output: {
path: path_resolve(__dirname, "dist"),
filename: 'bundle.js',
// filename: '[name].js' // 变量占位符,用于多出口
}
}
- 可以指定一个固定的文件名称,如果是多入口多出口(entry为对象),则不能使用单文件出口
- 通过webpack内置的变量占位符:[name]
深入
执行简要流程
entry -> loaders -> plugins -> output
- loaders:核心内容之一,非js类型的模块处理,不同类型的模块的解析就是依赖不同的loader来实现的。
- plugins:一组webpack的插件,主要扩展webpack本身的一些功能,它们会运行在各种模块解析完成以后的打包编译阶段,比如对解析后的模块文件进行压缩等
Loaders
raw-loader
// 安装
npm install raw-loader --save-dev
module.exports = {
...
// 模块配置
// loader配置
module: {
// 非js模块的加载规则和需要调用的loader处理器
rules: [
// 每一个对象就是一个处理规则
{
test: /\.txt$/, // 被加载的模块特征:正则,一般通过被加载文件的后缀来进行判断
use: 'raw-loader' // 如果加载的模块文件满足上面的特征,则调用use中设定的loader进行处理
}
]
}
}
当webpack碰到不识别的模块的时候,webpack会在配置的module中进行该文件规则的查找
- rules就是我们为不同类型的文件定义的解析规则对应的loader,它是一个数组
- 每一种类型规则通过test选项来定义,通常我们会通过正则的方式来匹配文件后缀类型
- use针对匹配到文件类型,调用对应的loader进行处理
markdown-loader
// 安装
npm i -D markdown-loader html-loader
module.exports = {
...
module: {
rules: [
{
test: /\.md$/,
use: [
// 这里处理loader的顺序是由下至上
{
loader: 'html-loader' // 后处理
},
{
loader: 'markdown-loader' // 先处理,会处理成html格式
}
]
}
]
}
}
file-loader
把识别出的资源模块,移动到指定的输出目录,并且返回这个资源在输出目录的地址(字符串)
// 安装
npm i --save-dev file-loader
rules: [
...,
{
test: /\.(png|jpe?g|gif)$/,
use: {
loader: 'file-loader',
options: {
// placeholder 占位符[name] 源资源模块的名称 [ext] 源资源模块的后缀
name: "[name]_[hash].[ext]",
// 打包后的存放位置
outputPath: "./images",
// 打包后文件的 url,虚拟目录
publicPath: "./public"
}
}
}
]
url-loader
可以处理file-loader所有的事情,但是遇到图片格式的模块,可以选择性的把图片转成base64格式的字符串,并打包到js中,对小体积的图片比较合适,大图片不合适。
npm install --save-dev url-loader
rules:[
{
test: /\.(png|jpe?g|gif)$/,
use: {
loader: 'url-loader',
options: {
name: "[name]_[hash].[ext]",
outputPath: "./images",
publicPath: "./images",
limit: 100 // 小于100字节转成base64格式
}
}
}
]
css-loader
// 文件引用
import css from './css/common.css';
let styleElement = document.createElement('style');
styleElement.innerHTML = css[0][1];
document.head.appendChild(styleElement);
style-loader
// 文件直接引用
import './css/common.css';
// module配置
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
同一个任务的loader可以同时挂载多个,处理顺序为:从右到左,也就是先通过css-loader处理,然后反悔上理后的css字符串交给style-loader进行处理。
// 多个
rules: [
{
test: /\.css$/,
use: [
{
loader: 'style-loader',
options: {}
},
'css-loader'
]
}
]
Plugins
扩展webpack本身的一些功能,它们会运行在各种模块解析完成以后的打包编译阶段,比如对解析后的模块文件进行压缩等。打包之后,保存之前。
HtmlWebpackPlugin
打包结束后,自动生成一个html文件,并把打包生成的js模块引入到该html中
npm install --save-dev html-webpack-plugin
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...,
plugins: [
new HtmlWebpackPlugin({
title: 'my App', // 用来生成页面的title元素
filename: 'app.html', // 输出的HTML文件名,默认是index.html,也可以配置子目录
template: './src/html/index.html' // 模板文件路径,支持加载器loader
})
]
}
在html模版中,可以通过<%=htmlWebpackPlugin.options.xxx%>的方式获取配置的值
clean-webpack-plugin
删除(清理)构建目录
npm install --save-dev clean-webpack-plugin
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
...,
plugins: [
...,
new CleanWebpackPlugin(),
...
]
}
mini-css-extract-plugin
提取css到一个单独的文件中
npm install --save-dev mini-css-extract-plugin
const MiniCssExtractPlugin = rquire('mini-css-extract-plugin');
module.exports = {
...,
module: {
rules: [
{
test: /\.s[ac]ss$/,
use: [
{
loader: MinCssExtractPlugin.loader
},
'css-loader',
'sass-loader'
]
}
]
},
plugins: [
new MinCssExtractPlugin(
{
filename: '[name].css'
}
)
]
}
sourceMap
我们实际运行在浏览器的代码是通过webpack打包合并甚至压缩混淆过的代码,所以生成的代码并不利于我们的调试和错误定位,我们可以通过sourceMap来解决这个问题,sourceMap本质是一个记录了编译后代码与源代码的映射关系的文件,我们可以通过webpack的devtool选项来开启sourceMap
module.exports = {
mode: 'production',
devtool: 'source-map'
}
首先,编译后会为每一个编译文件生成一个对应的 .map 文件,同时在编译文件中添加一段对应的map文件引入代码
//# sourceMappingURL = xx.js.map
//*# sourceMappingURL = xx.css.map*/
同时,浏览器能够识别sourceMap文件,在sources面板中显示根据编译文件与对应的map文件定位到源文件中,有利于我们的调试和错误定位。
WebpackDevServer
安装webpackDevServer可以避免每次的代码修改都需要重新编译打包,刷新浏览器。
npm install --save-dev webpack-dev-server
启动命令
npx webpack-dev-server
或者package.json中添加scripts
...,
"scripts": {
"server": "webpack-dev-server"
}
}
修改webpack.config.js
module.exports = {
...,
devServer: {
static: {
directory: path.join(__dirname, 'public'),
},
compress: true,
port: 8081 // 端口
}
}
Proxy
处理后端请求时会出现跨域的问题,webpackDevServer内置了一个代理服务,通过内置代理就可以把我们的跨域请求转发目标服务器上(webpackDevServer内置的代理发送的请求属于后端 - node,不受同源策略限制),具体如下:
使用node模拟服务端接口
// 安装
npm i koa koa-router
npm i -g supervisor
// 启用
supervisor app
const Koa = require('koa');
const KoaRouter = require('koa-router');
const app = new Koa();
const router = new KoaRouter();
router.get('/getdata',async ctx => {
ctx.body = {
userName: 'zMouse',
gender: 'male'
}
})
app.use(router.routes());
app.listen(7777);
webpack.config.js 配置
devServer: {
port: 8081,
// // 我们的每次请求都会被devServer拦截,然后如同webpack中的loader,如果请求的url满足proxy中的某个规则的话,则把这个请求转发到另外一个服务器上
proxy: {
'/api': {
// 把原始请求中的域转成target的域
target: 'http://localhost:7777',
// 把请求路径中的 /api 去掉
pathRewrite: {
'^/api': ''
}
}
}
}
页面调用
async function getData() {
let res = await fetch('/api/getdata');
console.log(res);
let data = await res.text();
console.log(data)
}
getData();
网友评论