webpack打包后生成什么文件(webpack打包详解)
时间:2023-07-08 13:30:39
点击次数:10
一、Webpack 打包
需要解决ESM 存在兼容性问题通过模块化划分的文件比较多,网络请求频繁所有的前端资源都需要模块化,模块化是必要的需要编译代码,将高版本转化为低版本
1.1 webpack 概述
是一款前端整体的模块打包工具安装 yarn,webpack、webpack-cli通过yarn webpack运行程序,使文件压缩yarn webpack
1.2 webpack 配置
1.2.1 webpack 配置文件
默认使 src/index.js 作为入口,然后新的文件会存放在 dist/main.js对文件的操作可以配置在webpack.config.js文件中
const path = require("path")
module.exports = {
entry: "./src/index.js", // 指定打包的路径
output: { // 输出文件设置
filename: "bundle.js", // 文件名
path: path.join(__dirname, output) // 一定要是绝对路径
}
}
1.2.2 webpack 工作模式
webpack --mode development:开发模式,会加快打包的速度webpack --mode none:默认模式,会进行最原始的打包,不会对代码进行处理webpack --mode production:生产模式可以在运行时使用yarn webpack --mode 模式 进行运行或者配置 webpack.config.js中的 mode 属性直接设置模式
module.exports = {
entry: "./src/index.js", // 指定打包的路径
output: { // 输出文件设置
filename: "bundle.js", // 文件名
path: path.join(__dirname, output) // 绝对路径
},
mode: "development" // 设置相关的执行模式
}
1.2.3 webpack资源模块加载
css资源需要先安装css-loader,然后在webpack.config.js中设置module总的rules数组设置test获取的文件和use使用的方法运行后数据存放在指定的js文件中安装style-loader,use属性存在多个使用方法时用数组包裹,并且是从右向左依次加载
const path = require("path")
module.exports = {
entry: "./src/main.css", // 指定打包的路径
output: { // 输出文件设置
filename: "bundle.js", // 文件名
path: path.join(__dirname, output) // 绝对路径
},
mode: "none", // 设置相关的执行模式
module: {
rules: [ // 针对其他资源的配置
{
test: /.css$/, // 匹配打包的文件路径
use: ["style-loader","css-loader" ] // 指定匹配到的文件需要执行的loader
}
]
}
}
1.2.4 webpack导入资源模块
打包入口 -》运行入口通过import引入.css资源
// main.js
import creating from ./header.js
import ./main.css
const heading = creating()
document.body.append(heading)
// heading.js
import "./heading.css"
export default () => {
const ele = document.createElement(h2)
ele.textContent = "hello world"
ele.classList.add("heading")
ele.addEventListener("click", () => {
alert("hello wepack")
})
return ele
}
1.2.5 webpack 文件资源加载器
安装 file-loader,到webpack.config.js中进行配置在加载的js文件夹中导入设置publicPath设置默认加载的目录 ’/‘不能省略
const path = require("path")
module.exports = {
entry: "./src/index.js", // 指定打包的路径
output: { // 输出文件设置
filename: "bundle.js", // 文件名
path: path.join(__dirname, output), // 绝对路径
publicPath: "output/" // 加载的路径 / 不能省略
},
mode: "none", // 设置相关的执行模式
module: {
rules: [ // 针对其他资源的配置
{
test: /.css$/, // 匹配打包的文件路径
use: ["style-loader","css-loader" ] // 指定匹配到的文件需要执行的loader
},
{
test: /.png$/,
use: "file-loader"
}
]
}
}
1.2.6 data URL加载器
是一种直接表示文件内容的方式,base64编码需要 url-loader 插件小文件使用data URLs减少请求减少请求次数;大文件单独提取存放,提高加载速度将use属性设置为对象,其中loader属性依旧是加载器的名称options对象为配置属性,limit为限制的大小,小于这个限制的图片使用data URLs大于的采用file-loader
这种方式一定要安装file-loader和url-loader
{
test: /.png$/,
use: {
loader: "url-loader",
options: {
limit: 10 * 1024,
esModule: false // 新版本file-loader的esModule属性默认是true
}
}
}
1.2.7 加载器类型
编译转换类型,例如css-loader,转化为以js形式工作的css模块文件操作类型的加载器,将文件拷贝到输出的目录,同时导出文件路径,例如file-loader代码检查类,为了统一代码的风格,提高代码质量,例如eslint-loader
1.2.8 Webpack 与 ES 2015
webpack仅仅是完成打包工作,因为模块打包需要,所以需要处理import 和 export
需要配置babel-loader,并且需要安装babel-core核心 和 babel-preset-env规范
因为babel只是一个平台,所以需要在use中进行配置
{
test: /.js$/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"]
}
}
}
1.2.9 webpack加载资源的方式
遵循ESM的 import/export遵循commonjs的require(),require接收ESM默认参数时需要加.default属性获取遵顼AMD标准的define函数和require函数loader加载的非js也会触发资源加载,样式代码中的@import指令和url函数
css-laoder加载资源的两种方式
@import url(./heading.css); /* 加载资源样式 */
body {
color: greenyellow;
background-image: url(./icon.png); /* 先进行css-loader 发现其他格式的就交给其他格式的loader转化 */
background-size: cover;
}
html加载资源,比如image标签的src,不过需要先配置html-loader
{
test: /.html$/,
use: {
loader: html-loader, // 默认只会处理image标签的src属性
options: {
atts: [img:src, a:href] // 手动设置加载的标签和标签属性,需要html-loader是0.5.5版本
}
}
}
1.2.10 webpack核心工作原理
选择一个打包入口文件,解析每一个模块的依赖再根据配置的属性rules,选择加载器,解析相关的模块,输出到打包结果中loader机制是webpack 的核心
1.2.11 开发一个 loader
制作一个markdown文件
两种方法
一个函数中直接输出,不过return的一定是一个js格式的数据通过多个loader进行输出,完成转换
其实loader就是管道
const marked = require("marked")
module.exports = sourse => {
const html = marked(sourse)
// return `export default (${JSON.stringify(html)})` // 直接返回输出的字符串,
// 还可以 返回 html 字符串,交给下一个loader操作
return html
}
1.3 webpack常用插件
1.3.1 自动清除插入目录插件
clean-webpack-plugin 插件,清除遗留的文件在创建文件夹
const { CleanWebpackPlugin } = require("clean-webpack-plugin") // 导入插件
module.exports = {
plugins: [ // 配置插件的位置
new CleanWebpackPlugin() // 创建实例并且放到plugins数组中
]
}
1.3.2 自动生成使用打包结果的html
html-webopack-plugin 根目录下自建的html存在一些问题,比如引用的路径需要手动修改,template属性为模板,要想模板生效,不要配置html-loader可以在模板字符串中 通过 htmlWebpackPlugin 对象获取内部相关的属性
// plugins 数组中的设置
new HtmlWebpackPlugin({
title: "webpack plugin sample", // 设置html文件的title主体
meta: {
viewport: "width=device-width" // 视口宽度
},
template: "./src/index.html" // 参照的模板
})
./src/index.html
<h1><%= htmlWebpackPlugin.options.title %>
</h1>生成多个html文件,创建多个new HtmlWebpackPlugin()实例对象,设置filename属性来设置文件名
new HtmlWebpackPlugin({
filename: "about.html"
})
1.3.3 静态资源打包器
copy-webpack-plugin实例对象需要传入数组,数组内是要复制的地址,可以是通配符、文件路径、相对地址
new copyWebpackPlugin({ // 实例 copy插件 设置对象
patterns: [ // 设置地址
"public" // 指定的文件目录
]
})
1.3.4 开发一个插件
相对于 loader,plugin拥有更宽的能力范围plugin通过钩子机制实现 插件必须是一个函数或者是apply方法的对象
compilation获取的是操作过程中的信息结果
通过在生命周期的钩子中挂载函数实现扩展
class myPlugin {
apply (compliter) {
console.log("启动");
compliter.hooks.emit.tap("mypl", compilation => { // 注册函数,emit是输出文件前的事件挂载点
// compilitation 可以理解为此次打包的上下文,打包产生的过程中产生的结果都在这个数据中
for (const name in compilation.assets) {
// console.log(name); // 获取文件名
// console.log(compilation.assets[name].source()); // 获取文件内容
if (name.endsWith(".js")) {
const contents = compilation.assets[name].source()
const withComment = contents.replace(/\/\*\*+\//g, "")
compilation.assets[name] = {
source: () => withComment, // source 是将来要操作的数据
size: () => withComment.length // size 是必需的
}
}
}
})
}
}
1.4 webpack 提升开发体验
原始的需要编译=》打包=》运行应用=》刷新浏览器理想的方法1.以http server运行2.自动编译 + 自动刷新提供source Map 支持
1.4.1 实现自动编译
watch 工作模式,监视文件变化,自动重新打包yarn webpack --watch
1.4.2 实现自动刷新
webpack Dev Server 集成 自动编译和自动刷新浏览器将打包结果存放在内存中--open运行后会自动打开浏览器yarn webpack-dev-server --open自动刷新的问题页面刷新会丢失状态
1.4.3 webpack Dev Server 静态资源访问
在配置文件中设置 devServer配置对象
module.exports = {
devServer: {
contentBase: ["public"] // 配置静态路径,可以是数组、字符串
}
}
1.4.4 webpack Dev Server 代理API服务
webpack dev server 支持配置代理,避免了跨域请求的问题实验目标,将github API代理到开发服务器
devServer: {
contentBase: ["public"], // 配置静态路径,可以是数组、字符串
proxy: { // 用于配置代理的配置
"/api": { // 代理的请求路径前缀
// http://localhost:8080/api/user 相对于 https://api.github.com/api/user, 所有需要重写
target: "https://api.github.com", // 代理的目标
pathRewrite: { // 代理路径的重写
// http://localhost:8080/api/user 相对于 https://api.github.com/user
"^/api": "" // 将代理到的路径中以 /api 开头的路由替换为空
},
// 默认为 false 不能使用 localhost:8080 作为请求 gitHub 主机名
changeOrigin: true // true 会以实际代理的主机名进行请求
}
}
}
1.5 Source Map
调试和报错的基于运行代码运行代码和源代码之间完全不同,无法定位错误信息
1.5.1 源代码地图
映射转换过后的代码和源代码之间的关系.map的文件,内容是json格式version:文件使用的source map的版本sources:转换前原文件的名称names:代码中使用的成员名称 mappings:转译之后的字符与转移之前的字符的映射关系
Source Map 解决了源代码与运行代码不一致所产生的调试问题
1.5.2 webpack 配置 Source Map
在devtool属性中设置”source-map“,不过现在方法很多
devtool: "source-map" // 开发中配置的辅助工具
1.5.3 eval 模式
生成的速度最快,但是只能定位模块的名称,而不知道具体的行列信息不会生成source map文件,会在模块文件中最后一个eval末尾书写//# sourceURL=xxxxx地址
devtool: "eval"
const HtmlWebpackPlugin = require("html-webpack-plugin")
const allModes = [
eval,
cheap-eval-source-map,
cheap-module-eval-source-map,
eval-source-map,
cheap-source-map,
cheap-module-source-map,
inline-cheap-source-map,
inline-cheap-module-source-map,
source-map,
inline-source-map,
hidden-source-map,
nosources-source-map
]
module.exports = allModes.map(item => {
return {
mode: "none",
devtool: item,
entry: "./src/index.js",
output: {
filename: `js/${item}.js`
},
module: {
rules: [
{
test: /\.js$/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"]
}
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
filename: `${item}.html`
})
]
}
})
1.6 webpack HMR
HMR 全称 hot module replacement,模块热更新
运行的过程中实时替换,不会影响内容
1.6.1 HMR开启
集成在webpack-dev-server中开启只需要运行webpack-dev-server加上 --hot就会开启或者配置文件现在devServer中配置hot:true然后引入webpack中的属性.HotModuleReplacementPlugin()HMR不能开箱即用,需要手动处理模块热替换逻辑css样式文件经过loader处理
const webpack = require("webpack")
module.exports = {
……
devServer: {
hot: true // 开启热加载
},
plugins: [
new webpack.HotModuleReplacementPlugin() // 模块热加载插件
]
}
1.6.2 HMR API
在入口模块中添加module.hot.accept()注册模块更新的处理函数参数1,依赖模块的路径参数2,处理的函数这只是针对js的处理方案
let lastHeader = heading // 获取旧元素
module.hot.accept("./header.js", () => {
const value = lastHeader.innerHTML // 获取状态
document.body.remove(lastHeader)
const newHeading = creating()
newHeading.innerHTML = value // 将状态赋值给新的元素
document.body.append(newHeading)
lastHeader = newHeading
})
针对图片因为import获取的是对象的地址,所以会是实时变化的,因此icon一直是最新地址
import icon from "./icon.png"
module.hot.accept("./icon.png", () => {
img.src = icon
console.log(icon);
})
1.6.3 HMR 注意事项
处理热替换的代码不易被发现hot属性改为hotOnly,不会刷新,便于查看错误
// hot: true,
hotOnly: true,
1.7 生产环境优化
模式(mode)为不同的环境创建不同的配置
1.7.1 不同环境下的配置
根据不同环境导出不同配置一个环境一个人配置webpack.config.js 可以导出一个函数参数1为环境名参数 参数2运行过程中的所有参数
适用于小型项目
module.exports = (env, argv) => { // 环境名,运行过程中的所有参数
const config = {
entry: "./src/index.js", // 指定打包的路径
output: { // 输出文件设置
filename: "js/bundle.js", // 文件名
path: path.join(__dirname, dist), // 绝对路径
// publicPath: "dist/" // 加载的路径 / 不能省略
},
mode: "development", // 设置相关的执行模式
devtool: "eval", // 开发中配置的辅助工具
devServer: {
hot: true,
// hotOnly: true,
contentBase: ["public"], // 配置静态路径,可以是数组、字符串
},
module: {
rules: [ // 针对其他资源的配置
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
{
test: /\.png/,
use: {
loader: "url-loader",
options: {
limit: 10 * 1024,
esModule: false
}
}
},
{
test: /\.js$/,
use: {
loader: "babel-loader",
options: {
presets: ["@babel/preset-env"]
}
}
}
]
},
plugins: [ // 配置插件的位置
new HtmlWebpackPlugin({
title: "webpack plugin sample", // 设置html文件的title主体
meta: {
viewport: "width=device-width" // 视口宽度
},
template: "./src/index.html" // 参照的模板
}),
new webpack.HotModuleReplacementPlugin()
]
} // 开发模式
if (env === "production") {
config.mode = "production"
config.devtool = false
config.plugins = [
new CleanWebpackPlugin(),
new CopyWebpackPlugin([public]),
...config.plugins
]
}
return config
}
多文件配置,适合大型项目需要webpack-merge因为没有了默认配置文件,所以需要 --config 配置文件
// webpack.prod.js
const common = require("./webpack.common")
const { merge } = require("webpack-merge")
const { CleanWebpackPlugin } = require("clean-webpack-plugin")
const CopyWebpackPlugin = require("copy-webpack-plugin");
module.exports = merge(common, { // merge 类似于 assign(),但是merge可以用于重新改变值,并且是新的空间
mode: production,
plugins: [
new CleanWebpackPlugin(),
new CopyWebpackPlugin({ // 实例 copy插件 设置对象
patterns: [ // 设置地址
"public" // 指定的文件目录
]
})
]
})
1.7.2 definePlugin
为代码注入全局成员它是webpack内置插件,自定义数据
const webpack = require("webpack")
module.exports = {
entry: "./src/main.js",
output: {
filename: "main.js",
},
mode: "none",
plugins: [
new webpack.DefinePlugin({
API : JSON.stringify("123456")
})
]
}
1.8 代码优化配置—optimization
1.8.1 tree shaking (摇树)
摇掉代码中未引用的部分生产模式下自动开启tree-shaking不是配置选项,它是功能搭配使用的效果minimize:相当于清除枯树叶usedexports:相当于标记枯树叶
const webpack = require("webpack")
module.exports = {
……,
optimization : { // 集中配置webpack内部优化功能
usedExports: true, // 只输出外部使用的成员
minimize: true // 开启压缩
}
}
1.8.2 合并模块
通过concatenateModules属性设置尽可能将多的模块合并到一个模块
module.exports = {
……,
optimization : { // 集中配置webpack内部优化功能
usedExports: true, // 只输出外部使用的成员
concatenatemodules: true // 合并尽可能多的模块
}
}
1.8.3 tree-shaking 与 babel
tree-shaking必须是使用 ES module 的模块化babel则是将所有的模块转换为commonjs格式,所以tree-shaking不会生效新版本中针对这个问题进行了优化,但是最保险的方法还是设置一下{modules: false},关闭 ESM转化
module.exports = {
……,
rules: [
{
test: /\.js$/,
use: {
loader: "babel-loader",
options: {
presets: [
["@babel/preset-env", { modules: false }] // 默认属性是modules属性默认值是auto,自动转换 ESM 插件是否开启
]
}
}
}
],
……
}
1.8.4 sideEffects —副作用
模块除了导出成员外是否做了其他事情一般用于 npm 包标记是都有副作用,webpack配置文件设置 sideEffects: true,开启这个标识,production模式下自动开启;在package.json中设置sideEffects:true/false,注明这个代码是否有副作用sideEffects是把未使用但无副作用的模块一并删除,tree-shaking只是删除未使用的,但是不知道是否有其他作用两者配合可以极大的优化代码// webpack.config.js
module.exports = {
……,
optimization: { // 集中配置webpack内部优化功能
usedExports: true, // 只输出外部使用的成员
sideEffects: true, // 开启副作用插件
// minimize: true // 开启压缩
}
}
// package.json
{
……,
"sideEffects": false // 是否有副作用
}
必须确保没有副作用才能用false
否则用数组标注有副作用的文件
css文件会被当作副作用文件
// package.json
{
……,
"sideEffects": ["./src/a.js", "./src/*.css"] // 有副作用的文件
}
1.9 code splitting—代码分包
总是合并代码,合并的文件可能非常大分包和按需加载
1.9.1 多入口打包
各个部分需要单独提取在entry中配置对象,属性名为随意,最好是文件名,属性只是文件路径output.filename改为“[name].bundle.js”,[name]会动态匹配entry的属性名在htmlwebpackplugin插件中设置chunks:["名字"]
module.exports = {
mode: none,
entry: {
index: ./src/index.js,
album: ./src/album.js
},
output: {
filename: [name].bundle.js // [name]会动态命名
},
……,
plugins: [
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
title: Multi Entry,
template: ./src/index.html,
filename: index.html,
chunks: [index] // 允许插入到模板中的chunks
}),
new HtmlWebpackPlugin({
title: Multi Entry,
template: ./src/album.html,
filename: album.html,
chunks: [album]
})
]
}
1.9.2 提取公共模块
在optimization中设置splitChunks对象,chunks:"all"optimization: {
splitChunks: {
// 自动提取所有公共模块到单独 bundle
chunks: all
}
}
1.9.3 动态导入
按需加载,提高应用响应效率通过import()方法引入,参数为地址和函数,函数的参数为模块输出的成员
const render = () => {
const hash = window.location.hash || #posts
const mainElement = document.querySelector(.main)
mainElement.innerHTML =
if (hash === "#post") {
import("./posts/posts.js").then(({ default: posts }) => { // 获取成员
document.body.appendChild(posts)
})
} else if (hash === "#album") {
import("./album/album.js").then(({ default: album }) => {
document.body.appendChild(album)
})
}
}
1.9.4 魔法注释
目的是将打包的文件进行重命名/ webpackChunkName:名字 /,固定格式如果名称相同则会合并
if (hash === "#post") {
import(/*webpackChunkName: "auble" */"./posts/posts.js").then(({ default: posts }) => {
document.body.appendChild(posts)
})
} else if (hash === "#album") {
import("./album/album.js").then(({ default: album }) => {
document.body.appendChild(album)
})
}
1.9.5 MiniCssExtractPlugin
目的是提取打包后的css,先安装mini-css-extract-plugin为了实现css样式的按需加载在插件中新建,在rules中用 minicssextractplugin.loader 替换style-loader超过150kb使用效果更好
const { CleanWebpackPlugin } = require(clean-webpack-plugin)
const HtmlWebpackPlugin = require(html-webpack-plugin)
const MiniCssExtractPlugin = require("mini-css-extract-plugin")
module.exports = {
mode: none,
entry: {
main: ./src/index.js
},
output: {
filename: [name].bundle.js
},
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
css-loader
]
}
]
},
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
linkType: text/css,
})
]
}
1.9.6 optimize-css-assets-webpack-plugin
压缩提取的css文件官方建议插件在optimization.minimizer中设置,但是需要重新定义js的压缩插件
1.10 输出文件名hash
hash:整个项目级别的,有变换就会全部变化chunkhash:同一路的打包都是一样的,同一个文件夹中的位置contenthash:文件级别的hash值,不同的文件就有不同的hash值
new MiniCssExtractPlugin({
filename: "[name]-[hash:8].bundle.css" // :num 限制位数
}
上一篇:
样机素材是什么格式(八个高质量样机素材网站分享(文末附56个打包好的样机素材模板下载链接))
下一篇:
如何制作网站模板(用这样的模板建站方法,2天快速完成网站建设)