import mk85 from ‘./assets/images/mk85.jpeg’
console.log(mk85) // mk85.jpeg
const img = document.createElement(‘img’)
img.src = mk85
const BoxDiv = document.getElementsByClassName(‘box’)
BoxDiv[0].appendChild(img)
运行webpack
命令看一下结果
实现图片在css文件中引入
在css中引入图片我们依旧使用url-loader,但需要对配置稍微进行修改css代码
.box {
width: 100px;
height: 100px;
/* background-color: yellowgreen; */
background-image: url(‘./assets/images/mk85.jpeg’);
display: flex;
}
直接引用并打包,打包成功!打开html页面,发现看不到图片,因为地址不对。打包后mk85图片在dist文件夹下,而index.css的引用路径依旧是mk85.jpeg,可index.css是在css文件夹下的,所以自然是无法引用到。那如何才能引用到呢?最简单的方法就是加上/
,但这里有坑(其实也不是坑,这是一个关于/images
、./images
、image
三者有什么不同的知识点)。补充:create-react-app也是通过/
实现引用统一的修改url-loader配置
const path = require(‘path’)
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)
const HtmlWebpackPlugin = require(‘html-webpack-plugin’)
const { CleanWebpackPlugin } = require(‘clean-webpack-plugin’)
module.exports = {
entry: ‘./src/index.js’,
output: {
filename: ‘main.js’,
path: path.resolve(__dirname, ‘./dist’)
},
mode: ‘development’,
module: {
rules: [
{
test: /.css$/,
use: [
MiniCssExtractPlugin.loader,
‘css-loader’,
‘postcss-loader’
]
},
{
test: /.(png|jpe?g|gif)$/,
use: {
loader: ‘url-loader’,
options: {
name: ‘[name].[ext]’,
limit: 1024 * 3,
outputPath: “images/”,
publicPath: “/images”,
}
}
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: “css/[name].css”,
}),
new HtmlWebpackPlugin({
template: ‘./src/index.html’
}),
new CleanWebpackPlugin()
]
}
-
outputPath表示输出的到哪里(file-loader提供的)
-
name: images/[name].[ext]
这样写和用outputPath设置效果一样吗?在配合publicPath字段时不一样。所以当你不需要配置publicPath字段时,可以通过name设置输出路径(file-loader提供的)
options: {
name: ‘[name].[ext]’,
limit: 1024 * 3,
outputPath: “images/”,
publicPath: “/images”,
}
// 等价于
options: {
name: ‘images/[name].[ext]’,
limit: 1024 * 3,
publicPath: “/”,
}
- publicPath表示资源引用的路径
运行webpack
命令看一下结果成功了!是我们想要的结果,不过问题又来了,当你打开html页面时发现并不能看到图片正常显示,这里就牵扯到关于/images
、./images
、image
三者有什么不同的知识点简单来说,如果我起了服务,我的实际路径就是“localhost:8080/images/mk85.jpeg”,如果没有起服务那就是“/images/mk85.jpeg”所以让我们开启一个服务吧!
实现webpack本地服务
安装webpack-dev-server
yarn add webpack-dev-server -D
配置url-loader
const path = require(‘path’)
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)
const HtmlWebpackPlugin = require(‘html-webpack-plugin’)
const { CleanWebpackPlugin } = require(‘clean-webpack-plugin’)
module.exports = {
entry: ‘./src/index.js’,
output: {
filename: ‘main.js’,
path: path.resolve(__dirname, ‘./dist’)
},
mode: ‘development’,
module: {
rules: [
{
test: /.css$/,
use: [
MiniCssExtractPlugin.loader,
‘css-loader’,
‘postcss-loader’
]
},
{
test: /.(png|jpe?g|gif)$/,
use: {
loader: ‘url-loader’,
options: {
name: ‘[name].[ext]’,
limit: 1024 * 3,
outputPath: “images/”,
publicPath: “/images”,
}
}
}
]
},
devServer: {
open: true,
port: 8080,
},
plugins: [
new MiniCssExtractPlugin({
filename: “css/[name].css”,
}),
new HtmlWebpackPlugin({
template: ‘./src/index.html’
}),
new CleanWebpackPlugin()
]
}
-
只需要加上devServer配置即可
-
open表示打开浏览器
-
port表示服务的端口号
注意:这时就不是使用webpack
命令来启动项目了,需使用webpack-dev-server
来启动
实现多页面打包
顾名思义,多页面自然是有多个html页面,每个html页面都有自己的js文件,那么,有多少个入口就要有多少个出口我们首先要设置一下目录形式,以适应多页面打包的形式(以下形式不是唯一的,但有助于大家的理解)
-
这里不需要src/index.js
-
新建一个webpack.multiple.config.js
-
新建src/pages/login/js/index.js
-
新建src/pages/main/js/index.js
安装glob,用于处理文件
yarn add glob -D
配置webpack.multiple.config.js
module.exports = {
entry: {
login: ‘./src/pages/login/js/index.js’,
main: ‘./src/pages/main/js/index.js’
},
output: {
filename: ‘[name].js’,
path: path.resolve(__dirname, ‘./dist’)
},
plugins: [
new HtmlWebpackPlugin({
template: ‘./src/index.html’,
filename: ‘login.html’,
chunks: [‘login’] // chunks的名字对应entry中的名字
}),
new HtmlWebpackPlugin({
template: ‘./src/index.html’,
filename: ‘main.html’,
chunks: [‘main’]
})
]
}
这样就完成了!你可以使用webpack --config ./`webpack.multiple.config.js
命令运行一下。结果会如你所愿的但是,这时你肯定会想难道我每写一个页面就重新配置一次吗?这也太麻烦了,也不优雅!那我们现在解决一下这个问题吧,直接上代码
// 我们写一个方法自动做我们上面配置的事情
const glob = require(“glob”)
const setMpa = () => {
const entry = {}
const htmlwebpackplugins = []
// 通过glob库拿到我们的入口文件数组
const entryFiles = glob.sync(path.resolve(__dirname, “./src/pages///index.js”))
// console.log(entryFiles)
// 打印结果
// [
// ‘/Users/yzy/Desktop/learnSpace/learnWebpack/src/pages/login/js/index.js’,
// ‘/Users/yzy/Desktop/learnSpace/learnWebpack/src/pages/main/js/index.js’
// ]
entryFiles.forEach((item) => {
const entryFile = item
const match = entryFile.match(/src/pages/(.*)/js/index.js$/)
// console.log(match)
// 打印结果
// [
// ‘src/pages/login/js/index.js’,
// ‘login’,
// index: 43,
// input: ‘/Users/yzy/Desktop/learnSpace/learnWebpack/src/pages/login/js/index.js’,
// groups: undefined
// ]
const pageName = match[1]
entry[pageName] = entryFile
htmlwebpackplugins.push(
new HtmlWebpackPlugin({
template: ./src/index.html
,
filename: ${pageName}.html
,
chunks: [pageName]
})
)
})
return {
entry,
htmlwebpackplugins,
}
}
有了这个方法以后,我们把它加到配置文件里
const path = require(‘path’)
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)
const HtmlWebpackPlugin = require(‘html-webpack-plugin’)
const { CleanWebpackPlugin } = require(‘clean-webpack-plugin’)
const glob = require(“glob”)
const setMpa = () => {
const entry = {}
const htmlwebpackplugins = []
const entryFiles = glob.sync(path.resolve(__dirname, “./src/pages///index.js”))
entryFiles.forEach((item) => {
const entryFile = item
const match = entryFile.match(/src/pages/(.*)/js/index.js$/)
const pageName = match[1]
entry[pageName] = entryFile
htmlwebpackplugins.push(
new HtmlWebpackPlugin({
template: ./src/index.html
,
filename: ${pageName}.html
,
chunks: [pageName]
})
)
})
return {
entry,
htmlwebpackplugins,
}
}
const { entry, htmlwebpackplugins } = setMpa()
module.exports = {
entry,
output: {
filename: ‘[name].js’,
path: path.resolve(__dirname, ‘./dist’)
},
mode: ‘development’,
module: {
rules: [
{
test: /.css$/,
use: [
‘style-loader’,
‘css-loader’,
‘postcss-loader’
]
},
{
test: /.(png|jpe?g|gif)$/,
use: {
loader: ‘url-loader’,
options: {
name: ‘[name].[ext]’,
limit: 1024 * 3,
outputPath: “images/”,
publicPath: “/images”,
}
}
}
]
},
devServer: {
open: true,
port: 8080,
hot: true
},
plugins: [
new MiniCssExtractPlugin({
filename: “css/[name].css”,
}),
new CleanWebpackPlugin(),
…htmlwebpackplugins
]
}
我们再使用webpack --config ./`webpack.multiple.config.js
命令运行一下,成功!
关注下方「前端开发博客」,回复 “加群”
加入我们一起学习,天天进步
小结
–
到这里就算是完成了一个简单的webpack项目配置,看到这里先不要着急往下看,思考一下是否真的了解了loader和plugin,如果让你写一个loader和plugin,你有思路吗我想不出意外的话,你应该是已经有了思路。如果没有也不用担心,看看下面的内容
实现一个loader
==========
先上链接,官网编写loader文档[11]首先loader是一个函数,注意这里不能是箭头函数编写一个替换字符串的loader
// replaceLoader.js
module.exports = function (soure) {
console.log(soure, this) // 这里可以自己打印看一下信息,内容太长我就不放进来了
return source.replace(‘hello webpack’, “你好呀,webpack!”)
}
-
loader是一个函数
-
不能使用箭头函数,因为要用到上下文的this
-
soure接收到的是待处理的文件源码
-
return处理后的文件源码,也是下一个loader接收到的文件源码
使用loader
{
test: /.js$/,
use: path.resolve(__dirname, ‘./loader/replaceLoader.js’)
}
运行webpack
命令看一下结果成功!是不是发现原来自定义loader这么简单,感兴趣可以自己尝试写一下css、png等其他文件的loader
实现一个plugin
==========
线上链接,官网编写plugin文档[12]同样简单,我们已经用了很多次plugin了,发现是不是都需要new一下。很显然,自定义loader是一个构造函数。我们看一下格式:
class PluginName {
constructor (options) {
}
apply(compiler) {
…
}
}
-
这里一定要写apply方法,webpack会通过apply方法启动插件
-
PluginName可以写成普通function,apply必须挂载到原型对象上(
PluginName.prototype
) -
class类中的apply不能写成箭头函数
-
webpack的compiler钩子[13],查看钩子决定你的插件要在哪一步做什么
编写一个假的html-webpack-plugin,输出一个fake.html文件
class HtmlPlugin {
constructor (options) {
}
apply(compiler) {
compiler.hooks.emit.tap(‘HtmlPlugin’, (compolation) => {
const content = ‘fake html’
compolation.assets[‘fake.html’] = {
source: function () {
return content
},
size: function () {
return content.length
}
}
})
}
}
module.exports = HtmlPlugin
使用这个plugin
plugins: [
new HtmlPlugin()
]
运行webpack
命令看一下结果成功!你也可以试着完善一下这个插件,加上配置,加上引入资源文件等
指纹策略
====
关于浏览器缓存
-
现代浏览器都会有缓存机制
-
当我们第一次访问A网站时,这时加载了y.js的文件进行了缓存
-
当我们第二次访问A网站时,浏览器发现缓存中已经有y.js了
-
缓存中有y.js那就用缓存的文件
-
优点:减少了资源的请求
-
缺点:当y.js的内容更新了,若不通过强制刷新浏览器的话则无法获取最新的y.js内容
-
我们加上标识符就可以解决这个问题了
-
第一次访问时加载了y.123.js
-
第二次访问发现有缓存就用缓存中的y.123.js
-
这时服务器中的y文件内容改变了,同时也修改了名字为y.111.js
-
第三次访问发现没有y.111.js文件,正确加载最新y.111.js
上诉都是比较简单解释,具体细节你可以不用知道,明白这个缓存机制的缓存方式即可
webpack中使用指纹策略
使用:
filename: ‘[name].[hash].[ext]’,
-
hash:以项目为单位,项目内容改变了,则会生成新的hash,内容不变则hash不变
-
整个工程任何一个需要被打包的文件发生了改变,打包结果中的所有文件的hash值都会改变
-
chunkhash:以chunk为单位,当一个文件内容改变,则整个chunk组的模块hash都会改变
-
假设打包出口有a.123.js和c.123.js
-
a文件中引入了b文件
-
修改了b文件的内容
-
重新的打包结果为a.111.js和c.123.js
-
a的hash值会被影响,但是c的hash值不受影响
-
contenthash:以自身内容为单位,依赖不算
-
假设打包出口有a.123js和b.123.css
-
a文件引入了b文件
-
修改了b文件的内容
-
重新打包结果为a.123.js和b.111.css
-
a的hash值不受影响
热模块替换
=====
你一定使用过这个功能,只是你不知道罢了!场景:
-
启动项目本地服务
-
修改了一个.css文件的内容
-
浏览器没有刷新,但是修改的内容还是生效了
这就是热模块替换,提示:无论是css还是js都可以做热模块替换,但是个人建议只做css的热模块替换即可。因为js的热模块替换需要写代码进行替换,除非特定情况下,否则js的热模块替换用处不大。我们来做一个css的热模块替换吧注:热模块替换不支持抽取出的css文件,只能放在style中,所以需要style-loader配置webpack.config.js
const path = require(‘path’)
const MiniCssExtractPlugin = require(‘mini-css-extract-plugin’)
const HtmlWebpackPlugin = require(‘html-webpack-plugin’)
const { CleanWebpackPlugin } = require(‘clean-webpack-plugin’)
const HtmlPlugin = require(‘./plugin/htmlPlugin’)
const Webpack = require(‘webpack’)
module.exports = {
entry: ‘./src/index.js’,
output: {
filename: ‘main.js’,
path: path.resolve(__dirname, ‘./dist’)
},
mode: ‘development’,
module: {
rules: [
{
test: /.js$/,
use: path.resolve(__dirname, ‘./loader/replaceLoader.js’)
},
{
test: /.css$/,
use: [
// MiniCssExtractPlugin.loader,
‘style-loader’,
‘css-loader’,
‘postcss-loader’
]
},
{
test: /.(png|jpe?g|gif)$/,
use: {
loader: ‘url-loader’,
options: {
name: ‘[name].[ext]’,
limit: 1024 * 3,
outputPath: “images/”,
publicPath: “/images”,
}
}
}
]
},
devServer: {
open: true,
port: 8080,
hot: true
},
plugins: [
new MiniCssExtractPlugin({
filename: “css/[name].css”,
}),
new HtmlWebpackPlugin({
template: ‘./src/index.html’
}),
new CleanWebpackPlugin(),
new HtmlPlugin(),
new Webpack.HotModuleReplacementPlugin()
]
}
思考了一下,还是附了一份完整的配置文件(有点担心这样太占页面位置了)
-
首先,将之前的MiniCssExtractPlugin.loader替换回style-loader
-
给devServer中加上
hot: true
-
引入webpack:
const Webpack = require('webpack')
-
在plugin中添加:
new Webpack.HotModuleReplacementPlugin()
运行webpack-dev-server
命令看看效果吧!
webpack5都更新了什么
==============
话不多说,直接上链接,webpack5更新的内容[14]提示:当你使用webpack4的时候,无论是装plugin(插件)还是loader都尽量看看该插件现在都有什么版本,如果发现版本从4.x一下子跳到了5.x,那么一定要去安装4.x的版本,否则在打包的时候会发生未知的错误
结尾
==
这篇文章最初只写到【搭建webpak项目】部分就发布并标记了未完待续,本想着后面的内容写的简洁一点(写详细了其实还是挺累的),但是看到有留言催更、表示很赞时,我决定一定要把这篇文章写好送给大家。截止此刻通过这篇文章我的粉丝从0变成了18,非常感谢大家的认同,这对我也是很大的鼓励。之后会努力写出好的文章分享给大家。最后,希望大家都不忘初心,共同进步成长!像我掘金的ID一样,祝大家KDDA(keep da dream alive)
关于本文
作者:KDDA_
https://juejin.cn/post/6953042611963691021
参考资料
[1]
https://github.com/postcss/autoprefixer
[2]
https://github.com/postcss/postcss
[3]
https://github.com/postcss/postcss#plugins
[4]
https://www.babeljs.cn/docs/plugins
[5]
https://www.babeljs.cn/docs/presets
[6]
https://webpack.js.org/configuration/mode/
[7]
https://webpack.docschina.org/plugins/mini-css-extract-plugin/
[8]
https://webpack.docschina.org/plugins/html-webpack-plugin/
[9]
https://github.com/jantimon/html-webpack-plugin#options
[10]
https://www.npmjs.com/package/clean-webpack-plugin
[11]
https://webpack.docschina.org/contribute/writing-a-loader/
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:前端)
_
https://juejin.cn/post/6953042611963691021
参考资料
[1]
https://github.com/postcss/autoprefixer
[2]
https://github.com/postcss/postcss
[3]
https://github.com/postcss/postcss#plugins
[4]
https://www.babeljs.cn/docs/plugins
[5]
https://www.babeljs.cn/docs/presets
[6]
https://webpack.js.org/configuration/mode/
[7]
https://webpack.docschina.org/plugins/mini-css-extract-plugin/
[8]
https://webpack.docschina.org/plugins/html-webpack-plugin/
[9]
https://github.com/jantimon/html-webpack-plugin#options
[10]
https://www.npmjs.com/package/clean-webpack-plugin
[11]
https://webpack.docschina.org/contribute/writing-a-loader/
小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数初中级前端工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!
因此收集整理了一份《2024年Web前端开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-itdihmWT-1710927728168)]
[外链图片转存中…(img-F62BZobw-1710927728168)]
[外链图片转存中…(img-XochqXhp-1710927728169)]
[外链图片转存中…(img-axVJq2zc-1710927728169)]
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频
如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注:前端)
[外链图片转存中…(img-uF3dZR4Z-1710927728169)]