webpack
webpack
是一个模块打包工具,可以把互相依赖的 html css js 以及图片、字体等资源文件,经过一系列的处理,打包成静态的前端项目。
为什么要使用 webpack?
在传统的前端项目中,需要引入大量的 css、js 等文件,不仅可能会导致命名冲突,还可能导致页面体积变大。
node 出现后带来了模块化开发,按需引入。
把 node 模块化的代码转化为 浏览器支持的代码。
在 webpack 中任何文件都可以使用 import 完成导入。webpack 是一个基于 nodejs 的框架。
初始化项目:
yarn init -y
加上 -y 的意思是生成的 package.json 文件所有的配置项,都取默认值。
添加 webpack 依赖:
yarn add webpack webpack-cli --dev
--dev 是将 webpack 相关的依赖安装到开发环境中,因为 webpack 只有在开发的时候用到,最终打包成的代码里面不需要再使用 webpack 了
在根目录创建一个 src 文件夹,是存放我们所有的源代码。
创建 index.js 和 index.html,并且进行引入。
使用 webpack 进行打包:
npx webpack
npx 可以让我们直接 node_modules 包下面安装好的自带的命令行,而不用写 node_modules 这一串的相对路径。
打包完成后,根目录会生成一个 dist 文件夹,文件夹下面会有一个 main.js 文件。即是我们打包后的文件。
可以将 html 中的引入 js 文件改成 dist 下面的 js 文件。
webpack 配置文件
webpack 最核心的部分是他的配置文件 webpack.config.js
。
可以修改入口的 js 文件,也就是说从哪个文件里面开始寻找 import 依赖的路径;
还可以配置出口,也就是最后生成的 js 文件的一些信息;
也可以通过 loader 加载不同类型的文件;
也可以通过 plugin 在打包的过程中对代码进行一些优化,或者是其他的操作。
webpack.config.js
里面使用的是 nodejs 的模块化语法:
使用 module.exports 导出一个空的对象。(配置详情在最下方)
module.exports={
...
}
加载 css 文件
需要安装两个 loader,不然会直接报错。
几乎所有关于 webpack 的依赖都安装在 开发者依赖中,因为在打包后就不需要了。
错误:Module parse failed: Unexpected token (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
yarn add --dev style-loader css-loader
安装完成之后需要在配置文件中去配置。
module: {
// 数组中每一个元素,都对应一个 loader 配置。每个 loader 的配置都包含匹配扩展名,以及使用哪些 loader 的相关的选项。
rules: [
// 配置 css loader
{
test: /\.css$/i, // 值是一个正则表达式,用于匹配文件,这里匹配所有以 .css 结尾的文件
use: ['style-loader', 'css-loader'], // use 表示使用哪些 loader
}
],
}
加载图片
对于图片等静态资源的文件,webpack 原生就支持,不需要额外的安装 loader。打包之后,图片的名字会变成随机的字符串。
// webpack 原生支持静态资源的匹配,因此不需要安装 额外的loader
{
test: /\.(png|svg|jpg|jpeg|gif)$/i, // 匹配多种图片的扩展名
type: 'asset/resource' // 因为使用内置的 loader ,则使用 type 属性
}
插件 plugin
HtmlWebpackPlugin
HtmlWebpackPlugin
。webpack 的插件自动生成 html 文件,可以防止引入出错。
yarn add html-webpack-plugin --dev
在配置文件中进行配置
// 引入
const HtmlWebpackPlugin = require('html-webpack-plugin');
// 配置
plugins: [
new HtmlWebpackPlugin()
],
再次打包后,会在 dist 目录中,生成一个 html 文件。
babel 转译 js 文件
将高版本js代码转换成低版本。
yarn add --dev babel-loader @babel/core @babel/preset-env
// js 文件 loader。babel
{
test: /\.js$/, // 所有 js 文件
exclude: /node_modules/, // 剔除 node_modules
use: {
loader: 'babel-loader', // 决定使用哪个 loader
options: { // options 给 loader 传递一些配置
presets: ['@babel/preset-env'], // 这样就可以转义代码了
}
}
}
压缩打包后的js代码
减少打包后的代码体积。
yarn add --dev terser-webpack-plugin
进行配置
// 优化
optimization: {
minimize: true, // 是否会压缩
minimizer: [
new TerserPlugin(),
], // 用什么工具进行压缩
},
DevServer
启动之后,如果我们修改了代码,他就会重新打包,刷新页面。
yarn add --dev webpack-dev-server
指定 dev server 从哪里加载代码。
// dev server 配置项
devServer: {
static:'./dist', // 指定 dist 目录
},
方便我们运行服务器,在 package.json 中添加 script。
启动 webpack serve 会自动打开浏览器
"scripts": {
"start": "webpack serve --open"
},
每次打包输出不同的文件名 hash
我们每次打包后的文件,dist 是一样的,但是浏览器会根据文件名进行缓存。
所以我们会给文件名添加一个随机的字符,每次更新之后都改为新的字符。
webpack 就会每次在打包后生成一个新的字符。
output: { // 出口
// filename: 'dist.js', // 配置打包后的文件名,此时是固定的。
// 可以配置为一个带有 hash,有不重复字符串的文件名
filename: '[name].[contenthash].js', // name 可以写死,如果用 [name] 会设置为 webpack 默认的文件名 main
path: path.resolve(__dirname, 'dist'), // 打包后的文件地址
},
指定路径别名
// 配置路径别名
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'), // 属性名就是路径别名,属性值就是真实的路径
}
}
可视化打包分析工具 bundle
有时候需要分析打包后哪个文件提交较大,则再进行优化。
yarn add --dev webpack-bundle-analyzer
进行配置
// 引入
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer');
plugins: [
new HtmlWebpackPlugin({ title: '设置网页标题' }),
new BundleAnalyzerPlugin.BundleAnalyzerPlugin(),
// 允许传递参数,自定义生成方式
],
配置详情
const HtmlWebpackPlugin = require('html-webpack-plugin');
const TerserPlugin = require("terser-webpack-plugin");
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer');
const path = require('path');
// 在这个对象里面配置 webpack 的配置项
module.exports = {
mode: 'development', // 模式。默认值为 production,共有三个参数:development、production、none
entry: './src/index.js', // 入口。单个入口语法。多个为:entry: ['./src/file_1.js', './src/file_2.js']
output: { // 出口
// filename: 'dist.js', // 配置打包后的文件名,此时是固定的。
// 可以配置为一个带有 hash,有不重复字符串的文件名
filename: '[name].[contenthash].js', // name 可以写死,如果用 [name] 会设置为 webpack 默认的文件名 main
path: path.resolve(__dirname, 'dist'), // 打包后的文件地址
},
// 配置路径别名
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'), // 属性名就是路径别名,属性值就是真实的路径
}
},
// 优化
optimization: {
minimize: true, // 是否会压缩
minimizer: [
new TerserPlugin(),
], // 用什么工具进行压缩
},
// dev server 配置项
devServer: {
static: './dist', // 指定 dist 目录
},
// 插件,插件的目的在于解决 loader 无法实现的其他事。webpack 提供很多开箱即用的插件。
// plugins 是一个数组,在这里可以配置多种插件。
// 由于插件可以携带参数或选项,因此在 webpack 配置中,向 plugins 属性传入一个 new 实例。
plugins: [
new HtmlWebpackPlugin({ title: '设置网页标题' }), // HtmlWebpackPlugin 简化了 html 文件的创建,以便为你的 webpack 包提供服务。
new BundleAnalyzerPlugin.BundleAnalyzerPlugin(),
// 允许传递参数,自定义生成方式
],
// 对于 loader,在 webpack 里面,我们需要先去匹配以什么样的扩展名文件应用什么样的 loader。
module: {
// 数组中每一个元素,都对应一个 loader 配置。每个 loader 的配置都包含匹配扩展名,以及使用哪些 loader 的相关的选项。
rules: [
// 配置 css loader。
{
test: /\.css$/i, // 值是一个正则表达式,用于匹配文件,这里匹配所有以 .css 结尾的文件。less 等也可以通过 加载对应的 loader 进行处理。
use: ['style-loader', 'css-loader'], // use 表示使用哪些 loader
},
// 图片 loader。 webpack 原生支持静态资源的匹配,因此不需要安装 额外的loader
{
test: /\.(png|svg|jpg|jpeg|gif)$/i, // 匹配多种图片的扩展名
type: 'asset/resource' // 因为使用内置的 loader ,则使用 type 属性
},
// js 文件 loader。babel
{
test: /\.js$/, // 所有 js 文件
exclude: /node_modules/, // 剔除 node_modules
use: {
loader: 'babel-loader', // 决定使用哪个 loader
options: { // options 给 loader 传递一些配置
presets: ['@babel/preset-env'], // 这样就可以转义代码了
}
}
}
],
}
}