webpack 快速入门教程
文章目录
webpack 是什么
webpack 是一种前端资源构建工具,一个静态模块打包器(module bundler)。
在 webpack 看来, 前端的所有资源文件(js/json/css/img/less/…)都会作为模块处理。 它将根据模块的依赖关系进行静态分析,打包生成对应的静态资源(bundle)。
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6jcc1KKp-1595555820303)(/Users/mxj/百度云同步盘/学习笔记/前端全栈/img/image-20200406095604708.png)]
官方中文文档参考:https://www.webpackjs.com/
模块打包,通俗地说就是:找出模块之间的依赖关系,按照一定的规则把这些模块组织合并为一个JavaScript文件。
webpack 的五个核心感念
名称 | 描述 |
---|---|
entry | 入口(Entry)指示 webpack 以哪个文件为入口起点开始打包,分析构建内部依赖图。 |
output | 输出(Output)指示 webpack 打包后的资源 bundles 输出到哪里去,以及如何命名。 |
loader | Loader(加载器) 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript) |
plugins | 插件(Plugins)可以用于执行范围更广的任务。插件的范围包括,从打包优化和压缩, 一直到重新定义环境中的变量等。 |
mode | 通过选择 development 或 production 之中的一个,来设置 mode 参数,你可以启用相应模式下的 webpack 内置的优化 |
webpack 安装与命令行打包
Webpack依赖Node.js,所以首先你要确保安装了 node.js。
Webpack的安装分为全局安装与本地安装,推荐使用本地安装。
全局安装的Webpack,在任何目录执行webpack命令都可以进行打包。而本地安装的Webpack,必须要找到对应node_modules下的webpack命令才能执行(在使用npx或package.json的scripts的时候,会自动帮助我们寻找)。
全局安装
# 全局安装最新稳定版本
npm install webpack webpack-cli -g
# 全局安装指定版本
npm install aaa@qq.com4.43.0 webpack-aaa@qq.com3.3.12 -g
# 全局安装指体验版本,目前(2020-7-10)体验版本是webpack5
npm install aaa@qq.com webpack-cli -g
本地安装
# 本地安装最新稳定版本,该命令是npm install webpack webpack-cli --save-dev的缩写
npm i webpack webpack-cli -D
全局安装与本地安装的Webpack是可以共存的。在大多数前端项目开发的时候,是需要本地安装的。因为只进行全局安装的话,可能因为版本不一致的问题导致本地项目跑不起来。
本地安装的Webpack,如果不想拼接路径,我们可以使用命令npx webpack,或者在package.json文件里写入下面的命令并执行npm run dev。这两种方式都会自动执行node_modules下的webpack命令,不需要我们把路径拼接上。
// ...
"scripts": {
"dev": "webpack"
},
// ...
使用方法
初始化一个npm项目并使用默认参数创建package.json文件。
npm init -y
安装了指定版本的webpack与webpack-cli。
npm install --save-dev aaa@qq.com aaa@qq.com
webpack是webpack核心包,webpack-cli是命令行工具包,在用命令行执行webpack的时候需要安装。
因为浏览器不支持原始 ES6 模块,所以不能直接将 ES6 的 JS 文件导入 html。我们可以通过Webpack把这两个文件打包成一个JS文件来解决这个问题。Webpack打包后,代码里就没有这种模块化语法了。
打包命令
a.js
import { name } from './b.js';
console.log(name);
b.js
export var name = 'Jack';
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="./bundle.js"></script>
</body>
</html>
执行打包命令
npx webpack a.js -o bundle.js
打包之后就可以把合并之前的文件删除了,即a.js、 b.js。
打包后的bundle.js代码目前是压缩后的,后面会讲解怎样不压缩打包后的代码。
我们在执行上面命令的时候,命令行控制台会出现警告信息,告诉我们没有设置’mode’项,Webpack将会使用默认的’production’。我们可以在上面的命令后面配上’mode’项,但当命令参数过长的时候,使用起来就会不方便。此时,我们可以选择使用Webpack的配置文件。
webpack 配置文件
Webpack默认的配置文件是项目根目录下的webpack.config.js,在我们执行下方命令的时候,
npx webpack
Webpack会自动寻找该文件并使用其配置信息进行打包。如果不存在会报错
我们可以手动创建 webpack.config.js 文件。
var path = require('path');
module.exports = {
entry: './a.js',
output: {
path: path.resolve(__dirname, ''),
filename: 'bundle.js'
},
mode: 'none'
};
命令行执行npx webpack后,Webpack就开始打包了。配置文件里的代码解释:
因为Webpack是基于Node.js执行的,所以可以使用Node的功能。path是Node.js里的路径解析模块,你可以将其看成是一个JS普通对象,该对象有一些方法可以供我们使用。我们现在使用了其resolve方法,该方法的作用是将方法参数解析成一个绝对路径返回。__dirname是Node.js的一个全局变量,表示当前文件的路径。这样,path.resolve(__dirname, ”)表示的其实就是当前文件夹根目录的绝对路径。
module.exports是CommonJS模块导出语法,导出的是一个对象,该对象的属性就是Webpack打包要使用的参数。entry是Webpack构建的入口文件,我们的入口文件是a.js。output是打包后资源输出文件,其中path表示输出的路径,filename表示输出的文件名,现在我们把打包后的文件输出在当前目录的bundle.js。
mode是Webpack的打包模式,默认是’production’,表示给生产环境打包的。现在我们设置成’none’,这样代码就不会压缩了。
入口起点
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EqXLDlTb-1595555820306)(/Users/mxj/百度云同步盘/学习笔记/前端全栈/自动化部署/img/webpack-tutorial-1024x454.png)]
图片里箭头开始的.js文件就是Webpack构建的资源入口,然后根据这个.js文件依赖的文件,把相关联的文件模块打包到一个.js文件,本质上来说,这个打包后得到的.js文件就是Webpack打包构建的资源出口。
当然,这个.js文件通常不是我们最终希望打包出来的资源,我们希望可以拆分成JS、CSS和图片等资源。
Webpack当然提供了这样的方法。在构建的时候,我们可以通过Webpack的预处理器loader和插件plugin等进行干预,把一个.js文件变成JS、CSS和图片等资源。
可以通过修改 webpack 配置的 entry 属性,来指定一个或多个入口路径。默认为 ./src。
webpack.config.js
module.exports = {
entry: './path/to/my/entry/file.js' //入口路径
};
webpack 基础目录(context)
context 官方称为基础目录,在Webpack中表示资源入口entry是从哪个目录为起点的。context的值是一个字符串,表示一个绝对路径。
下面的配置表示从工程根目录下src文件夹下的js文件夹里的a.js开始打包。
var path = require('path');
module.exports = {
context: path.resolve(__dirname, './src'),
entry: './js/a.js',
output: {
path: path.resolve(__dirname, ''),
filename: 'bundle.js'
},
mode: 'none'
};
一般我们不会去设置context,在我们没有设置context的时候,它是当前工程的根目录。
资源入口 entry
Webpack资源入口entry代表的路径,是相对路径。目前我们使用的entry都是字符串形式的,其实它还可以是数组、对象和函数形式。
-
字符串
字符串形式的我们已经在之前使用过了,是最简单的形式,表示打包的入口JS文件。
-
数组
module.exports = { entry: ['core-js/stable', 'regenerator-runtime/runtime', './a.js'], };
它表示的含义是数组最后一个文件是资源的入口文件,数组其余文件会预先构建到入口文件。
上面的配置和下面是等效的
a.js
import 'core-js/stable'; import 'regenerator-runtime/runtime';
webpack.config.js
module.exports = { entry: './a.js', };
数组形式的入口本质还是一个入口。
-
对象
入口entry是对象形式的又称之为多入口配置,本质上打包后生成多个JS文件。
var path = require('path'); module.exports = { entry: { app: ['core-js/stable', 'regenerator-runtime/runtime', './a.js'], vendor: './vendor' }, output: { path: path.resolve(__dirname, ''), filename: '[name].js' }, mode: 'none' };
上方的配置分别从两个入口文件打包,每个入口文件各自寻找自己依赖的文件模块打包成一个JS文件,最终得到两个JS文件。
-
函数
函数形式的入口,Webpack取函数返回值作为入口配置,返回值是上述3种之一即可。
函数形式的entry,可以用来做一些额外的逻辑处理,不过在自己搭脚手架的很少使用。
常见场景
分离 应用程序(app) 和 第三方库(vendor) 入口
webpack.config.js
const config = {
entry: {
app: './src/app.js',
vendors: './src/vendors.js'
}
};
多页面应用程序
webpack.config.js
const config = {
entry: {
pageOne: './src/pageOne/index.js',
pageTwo: './src/pageTwo/index.js',
pageThree: './src/pageThree/index.js'
}
};
这个告诉 webpack 需要 3 个独立分离的依赖图(如上面的示例)。
在多页应用中,每当页面跳转时服务器将为你获取一个新的 HTML 文档。页面重新加载新文档,并且资源被重新下载。
输出
output 属性告诉 webpack 在哪里输出它所创建的 bundles,以及如何命名这些文件,默认值为 ./dist
。基本上,整个应用程序结构,都会被编译到你指定的输出路径的文件夹中。你可以通过在配置中指定一个 output
字段,来配置这些处理过程:
webpack.config.js
const path = require('path');
module.exports = {
entry: './path/to/my/entry/file.js',
output: {
path: path.resolve(__dirname, 'dist'), //输出路径
filename: 'my-first-webpack.bundle.js' //用于输出文件的文件名。
}
};
配置 output
选项可以控制 webpack 如何向硬盘写入编译文件。注意,即使可以存在多个入口
起点,但只指定一个输出
配置。
publicPath
publicPath 指定静态资源路径,当使用 webpack 打包时会将打包文件放进指定的目录中。
当使用 webpack-dev-server 时可以不用设置publicPath,因为该插件内置的库会自动在根目录下生成 index.html。
webpack-dev-server 会把打包后的文件放到项目的根目录下,文件名是在output配置中的filename. 但是当有publicPath 配置的时候,就不一样了。Webpack 会把所有的文件打包到publicPath指定的目录下,就是相当于在项目根目录下创建了一个publicPath目录, 然后把打包成的文件放到了它里面,只不过我们看不到而已, 文件名还是output配置中的filename。
模式
提供 mode
配置选项,告知 webpack 使用相应模式的内置优化。
语法
module.exports = {
mode: 'production'
};
或者从 CLI 参数中传递:
webpack --mode=production
支持以下字符串值:
选项 | 描述 |
---|---|
development | 会将 process.env.NODE_ENV 的值设为 development 。启用 NamedChunksPlugin 和 NamedModulesPlugin 。 |
production | 会将 process.env.NODE_ENV 的值设为 production 。启用 FlagDependencyUsagePlugin , FlagIncludedChunksPlugin , ModuleConcatenationPlugin , NoEmitOnErrorsPlugin , OccurrenceOrderPlugin , SideEffectsFlagPlugin 和 UglifyJsPlugin . |
loader
Loader是Webpack生态里一个重要的组成,我们一般称之为预处理器。
loader 用于对模块的源代码进行转换。loader 可以将文件从不同的语言(如 TypeScript)转换为 JavaScript,或将内联图像转换为 data URL。loader 甚至允许你直接在 JavaScript 模块中 import
CSS文件!因为 webpack 只解析 js/json 格式的文件,所以当需要给 css、图片打包时需要用到 loader。
loader 可以使你在 import
或"加载"模块时预处理文件。
安装 loader
这里我们安装两个loader,分别是css-loader与style-loader。
其中css-loader是必需的,它的作用是解析CSS文件,包括解析@import等CSS自身的语法。它的作用也仅仅是解析CSS文件,它会把CSS文件解析后,以字符串的形式打包到JS文件中。不过,此时的CSS样式并不会生效,因为我们需要把CSS插入到html里才会生效。
此时,style-loader就来发挥作用了,它可以把JS里的样式代码插入到html文件里。它的原理很简单,就是通过JS动态生成style标签插入到html文件的head标签里。
npm install --save-dev css-loader
npm install --save-dev style-loader
// 合并写法
npm install -S css-loader style-loader
在 webpack 的配置中 loader 有两个目标:
-
test
属性,用于标识出应该被对应的 loader 进行转换的某个或某些文件。 -
use
属性,表示进行转换时,应该使用哪个 loader。
webpack.config.js
const path = require('path');
const config = {
output: {
filename: 'my-first-webpack.bundle.js'
},
module: {
rules: [
{
test: /\.css/, //正则匹配将要打包的文件格式
use: ['style-loader', 'css-loader'] //使用的加载器
}
]
}
};
module.exports = config;
可以看到,我们需要对配置项新增module,该项是一个对象,其rules里是我们对各个类型文件的处理规则配置。
use值是一个数组,每一项是一个loader。loader的执行顺序是从后向前执行,先执行css-loader,然后把css-loader执行的结果交给style-loader执行。
现在我们执行npx webpack来完成打包,然后在浏览器打开index.html,发现CSS生效了。
使用
-
webpack配置(推荐):在 webpack.config.js 文件中指定 loader。
-
内联:在每个
import
语句中显式指定 loader。import Styles from 'style-loader!css-loader?modules!./styles.css';
-
cli
你也可以通过 CLI 使用 loader:
webpack --module-bind jade-loader --module-bind 'css=style-loader!css-loader'
这会对
.jade
文件使用jade-loader
,对.css
文件使用style-loader
和css-loader
。
plugins
插件目的在于解决 loader 无法实现的其他事。
webpack 插件是一个具有 apply
属性的 JavaScript 对象。apply
属性会被 webpack compiler 调用,并且 compiler 对象可在整个编译生命周期访问。
用法
由于插件可以携带参数/选项,你必须在 webpack 配置中,向 plugins
属性传入 new
实例。
配置
webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin'); //通过 npm 安装
const webpack = require('webpack'); //访问内置的插件
const path = require('path');
const config = {
entry: './path/to/my/entry/file.js',
output: {
filename: 'my-first-webpack.bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.(js|jsx)$/,
use: 'babel-loader'
}
]
},
plugins: [
new webpack.optimize.UglifyJsPlugin(),
new HtmlWebpackPlugin({template: './src/index.html'})
]
};
module.exports = config;
webpack 初体验
初始化配置
(1)初始化 package.json
npm init
(2)下载并安装 webpack
npm install webpack webpack-cli -g //全局安装
npm install webpack webpack-cli -D //局部安装
当电脑上全局安装 webpack 时也需要局部安装,因为在运行的项目所使用的 webpack 版本可能低于当前电脑中的版本,这时需要安装指定版本的 webpack
npm install aaa@qq.com
编译打包应用
-
创建文件
-
运行指令
开发环境指令:webpack src/js/index.js -o build/js/built.js --mode=development 功能:webpack 能够编译打包 js 和 json 文件,并且能将 es6 的模块化语法转换成浏览器能识别的语法。 生产环境指令:webpack src/js/index.js -o build/js/built.js --mode=production 功能: 在开发配置功能上多一个功能,压缩代码。
-
结论
webpack 能够编译打包 js 和 json 文件。
能将 es6 的模块化语法转换成浏览器能识别的语法。 能压缩代码。 -
问题
不能编译打包 css、img 等文件。
不能将 js 的 es6 基本语法转化为 es5 以下语法。
开发环境基本配置
打包样式资源
(1)新建文件
(2)下载安装包
npm i css-loader style-loader less-loader less -D
(3)修改配置文件
// resolve 用来拼接绝对路径的方法 const { resolve } = require('path');
module.exports = {
// webpack 配置
// 入口起点
entry: './src/index.js',
// 输出
output: {
// 输出文件名
filename: 'built.js',
// 输出路径
// __dirname nodejs 的变量,代表当前文件的目录绝对路径 path: resolve(__dirname, 'build')
},
// loader 的配置 module: {
rules: [
// 详细 loader 配置
// 不同文件必须配置不同 loader 处理 {
// 匹配哪些文件
test: /\.css$/,
// 使用哪些 loader 进行处理 use: [
// use 数组中 loader 执行顺序:从右到左,从下到上 依次执行
// 创建 style 标签,将 js 中的样式资源插入进行,添加到 head 中生效 'style-loader',
// 将 css 文件变成 commonjs 模块加载 js 中,里面内容是样式字符串 'css-loader'
] },
{
test: /\.less$/,
use: [
'style-loader', 'css-loader',
// 将 less 文件编译成 css 文件 // 需要下载 less-loader 和 less 'less-loader'
] }
] },
// plugins 的配置 plugins: [
// 详细 plugins 的配置 ],
// 模式
mode: 'development', // 开发模式 // mode: 'production'
}
(4)运行指令 webpack
打包 html 资源
(1)新建文件
(2)安装命令
npm install --save-dev html-webpack-plugin
(3)修改配置
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
// loader 的配置 ]
}, plugins: [
// plugins 的配置
// html-webpack-plugin
// 功能:默认会创建一个空的 HTML,自动引入打包输出的所有资源(JS/CSS) // 需求:需要有结构的 HTML 文件
new HtmlWebpackPlugin({
// 复制 './src/index.html' 文件,并自动引入打包输出的所有资源(JS/CSS)
template: './src/index.html'
})
],
mode: 'development'
};
(4)执行指令 webpack
打包图片资源
(1)新建文件
(2)下载安装包
npm install --save-dev html-loader url-loader file-loader
(3)修改配置
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.less$/,
// 要使用多个 loader 处理用 use
use: ['style-loader', 'css-loader', 'less-loader']
}, {
// 问题:默认处理不了 html 中 img 图片 // 处理图片资源
test: /\.(jpg|png|gif)$/,
// 使用一个 loader
// 下载 url-loader file-loader loader: 'url-loader', options: {// 图片大小小于8kb,就会被base64处理
// 优点: 减少请求数量(减轻服务器压力)
// 缺点:图片体积会更大(文件请求速度更慢)
limit: 8 * 1024,
// 问题:因为url-loader默认使用es6模块化解析,而html-loader引入图片是commonjs // 解析时会出问题:[object Module]
// 解决:关闭 url-loader 的 es6 模块化,使用 commonjs 解析
esModule: false,
// 给图片进行重命名
// [hash:10]取图片的 hash 的前 10 位
// [ext]取文件原来扩展名
name: '[hash:10].[ext]'
} },
{
test: /\.html$/,
// 处理 html 文件的 img 图片(负责引入 img,从而能被 url-loader 进行处理) loader: 'html-loader'
} ]
}, plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}) ],
mode: 'development'
};
(4)运行指令: webpack
打包其他资源
其他资源值的是除 css、图片、html 之外的资源
(1)新建文件
(2)修改配置
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
// 打包其他资源(除了html/js/css资源以外的资源) {
// 排除 css/js/html 资源
exclude: /\.(css|js|html|less)$/, loader: 'file-loader',
options: {
name: '[hash:10].[ext]'
}
} ]
}, plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
})
],
mode: 'development'
};
devserver
修改配置
const { resolve } = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
entry: './src/index.js',
output: {
filename: 'built.js',
path: resolve(__dirname, 'build')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
},
// 打包其他资源(除了html/js/css资源以外的资源) {
// 排除 css/js/html 资源
exclude: /\.(css|js|html|less)$/,
loader: 'file-loader',
options: {
name: '[hash:10].[ext]'
}
} ]
}, plugins: [
new HtmlWebpackPlugin({
template: './src/index.html'
}) ],
mode: 'development',
devServer: {
// 项目构建后路径
contentBase: resolve(__dirname, 'build'), // 启动 gzip 压缩
compress: true,
// 端口号
port: 3000,
// 自动打开浏览器
open: true
} };
运行指令: npx webpack-dev-server
上一篇: JDK8新特性