案例
我们先尝试一下直接引入图片然后打包项目,看看是什么情景
项目目录
代码
index.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <!-- 解决没有favicon.ico时报错GET http://localhost:9999/favicon.ico 404 (Not Found) --> <link rel="shortcut icon" href="#" /> <title>webpack学习</title> </head> <body> <div>这是webpack学习</div> <div id="root"></div> <script src="./dist/main.js"></script> </body> </html>
index.js
const starImg = require('./src/assets/star.png'); const dom = document.getElementById('root'); const imgBox = new Image(); imgBox.src = starImg; dom.append(imgBox);
webpack.config.js
const path = require('path'); // 由于webpack无法直接操作文件夹,所以需要引入node的path模块 module.exports = { // entry: './index.js', // 指定当前目录的index.js为打包的入口文件 entry: { main: './index.js', // 指定当前目录的index.js为打包的入口文件 // 实际上是 entry: './index.js' 的具体写法,main为打包的Chunk Name // sub: './postcss.config.js', // 可以有多个入口文件,指定当前目录的postcss.config.js为打包的入口文件 }, mode: 'development', // mode 指定打包模式(development(不会被压缩),production(这个模式的话代码会被压缩)) // development默认配置了sourcemap // development默认无tree shaking配置,需要额外配置 output: { // filename: '[name].[contenthash].js', // contenthash,根据content(代码内容)产生的hash值,如果代码不变,contenthash就不会变,否则就会变,主要为了解决浏览器缓存因为名字不变,更新代码后不重新请求更新后文件的问题 // chunkFilename: '[name].[contenthash].chunk.js', // contenthash,根据content(代码内容)产生的hash值,如果代码不变,contenthash就不会变,否则就会变,主要为了解决浏览器缓存因为名字不变,更新代码后不重新请求更新后文件的问题 filename: '[name].js', // 打包后输出的打包文件的文件名,根据entry的chunk name作为输出文件名(如果entry有多个入口文件时必须用占位符这样设置output.filename) // filename: '[name].[chunkhash].js', // 打包后输出的打包文件的文件名,根据entry的chunk name + chunkhash(解决缓存不更新的问题)作为输出文件名(如果entry有多个入口文件时必须用占位符这样设置output.filename) // chunkFilename: '[name].chunk.js', // 入口文件走filename,其他非入口文件是index.js引入(同步引入或者异步引入)的间接js文件(非入口文件),如果打包生成的间接js文件,是走chunkFilename path: path.resolve(__dirname, 'dist'), // 指定打包后输出的打包文件在当前webpack.config.js所在文件夹的绝对路径的dist文件夹下 // path值必须是绝对路径 ,所以引入path包,__dirname代表当前webpack.config.js所在文件夹的绝对路径 // 整体路径为第一个参数+第二个参数,即__dirname + dist // 是所有输出文件的目标路径(物理路径, 存储路径); publicPath: '/' // (url 相对于 HTML 页面所在文件夹的绝对路径 + 值)给output配置全局的publicPath, // 这样各个loader打包出来的文件发布路径(引用地址)就是此全局publicPath + loader的options.outputPath // (文件引用路径就是看这个) // 是对页面引入资源的补充,比如img标签引入或者css引入等. // 千万不能设错,应该观察文件和HTML页面的存储地址位置,进行设置,否则引用时地址会错误,找不到文件 // publicPath: 'http://www.cdn.cn' // 如果,想把打包后生成的index.html作为入口文件,而打包生成的js放到服务器上如http://www.cdn.cn,那么webpack就应该这样设置 } }
package.json
{ "name": "01_why_use", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "bundle": "webpack" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "webpack": "^4.43.0", "webpack-cli": "^3.3.11" } }
打包
执行npm run bundle
打包结果如下,报错了,提示我们需要通过一个loader来处理star.png图片
loader
在编写前端页面的时候,我们总是时常需要引入一些图片进行展示,那么如何利用webpack将图片打包进我们的项目中呢?
webpack默认是可以处理js文件的,但是它不能直接处理jpg,gif,png图片等静态资源,因此我们需要可以处理jpg,gif,png图片等静态资源的loader
loader就是一个打包方案,对于特定文件,loader可以告诉webpack如何打包这些文件,webpack不识别非js结尾的文件,就需要loader告诉webpack如何打包这些文件(如果需要打包的文件不是以js为后缀,就要考虑使用loader了)
在更高层面,webpack的loader有两个属性
test属性:用于标识出应该被对应的loader进行转换的某个或某些文件
use属性:表示进行转换时,应该使用哪个loader
url-loader
我们可以通过url-loader或者file-loader进行图片的打包处理,这里我们以url-loader为例
安装url-loader
npm i url-loader file-loader -D
配置webpack
webpack.config.js
const path = require('path'); // 由于webpack无法直接操作文件夹,所以需要引入node的path模块 module.exports = { // entry: './index.js', // 指定当前目录的index.js为打包的入口文件 entry: { main: './index.js', // 指定当前目录的index.js为打包的入口文件 // 实际上是 entry: './index.js' 的具体写法,main为打包的Chunk Name // sub: './postcss.config.js', // 可以有多个入口文件,指定当前目录的postcss.config.js为打包的入口文件 }, mode: 'development', // mode 指定打包模式(development(不会被压缩),production(这个模式的话代码会被压缩)) // development默认配置了sourcemap // development默认无tree shaking配置,需要额外配置 module: { rules: [ { test: /\.(jpg|png|gif)$/, // 对文件类型后缀进行匹配 use: { loader: 'url-loader', // 使用url-loader对图片进行打包,如果url-loader的options没有设置limit,默认将所有静态文件全部打包成base64的字符串放到js里 options: { name: '[name]_[hash].[ext]', // 输出的文件名为[原名称]_[哈希值].[原后缀] outputPath: 'images/', // 文件存储路径(output.path + 值)(物理路径, 存储路径) // 负责输出目录, 即打包后的写在磁盘的位置 } } }, ] }, output: { // filename: '[name].[contenthash].js', // contenthash,根据content(代码内容)产生的hash值,如果代码不变,contenthash就不会变,否则就会变,主要为了解决浏览器缓存因为名字不变,更新代码后不重新请求更新后文件的问题 // chunkFilename: '[name].[contenthash].chunk.js', // contenthash,根据content(代码内容)产生的hash值,如果代码不变,contenthash就不会变,否则就会变,主要为了解决浏览器缓存因为名字不变,更新代码后不重新请求更新后文件的问题 filename: '[name].js', // 打包后输出的打包文件的文件名,根据entry的chunk name作为输出文件名(如果entry有多个入口文件时必须用占位符这样设置output.filename) // filename: '[name].[chunkhash].js', // 打包后输出的打包文件的文件名,根据entry的chunk name + chunkhash(解决缓存不更新的问题)作为输出文件名(如果entry有多个入口文件时必须用占位符这样设置output.filename) // chunkFilename: '[name].chunk.js', // 入口文件走filename,其他非入口文件是index.js引入(同步引入或者异步引入)的间接js文件(非入口文件),如果打包生成的间接js文件,是走chunkFilename path: path.resolve(__dirname, 'dist'), // 指定打包后输出的打包文件在当前webpack.config.js所在文件夹的绝对路径的dist文件夹下 // path值必须是绝对路径 ,所以引入path包,__dirname代表当前webpack.config.js所在文件夹的绝对路径 // 整体路径为第一个参数+第二个参数,即__dirname + dist // 是所有输出文件的目标路径(物理路径, 存储路径); publicPath: '/' // (url 相对于 HTML 页面所在文件夹的绝对路径 + 值)给output配置全局的publicPath, // 这样各个loader打包出来的文件发布路径(引用地址)就是此全局publicPath + loader的options.outputPath // (文件引用路径就是看这个) // 是对页面引入资源的补充,比如img标签引入或者css引入等. // 千万不能设错,应该观察文件和HTML页面的存储地址位置,进行设置,否则引用时地址会错误,找不到文件 // publicPath: 'http://www.cdn.cn' // 如果,想把打包后生成的index.html作为入口文件,而打包生成的js放到服务器上如http://www.cdn.cn,那么webpack就应该这样设置 } }
- npm run bundle,打包
发现报错了,资源引用路径变成了[object Module]
这是因为新版本url-loader 的esModule默认为true,会导致图片的地址变为[object Module],因此这里设置为false(备注:如果是使用file-loader打包图片,也会碰到同样的文件,用同样的解决办法即可)
修改webpack.config.js
const path = require('path'); // 由于webpack无法直接操作文件夹,所以需要引入node的path模块 module.exports = { // entry: './index.js', // 指定当前目录的index.js为打包的入口文件 entry: { main: './index.js', // 指定当前目录的index.js为打包的入口文件 // 实际上是 entry: './index.js' 的具体写法,main为打包的Chunk Name // sub: './postcss.config.js', // 可以有多个入口文件,指定当前目录的postcss.config.js为打包的入口文件 }, mode: 'development', // mode 指定打包模式(development(不会被压缩),production(这个模式的话代码会被压缩)) // development默认配置了sourcemap // development默认无tree shaking配置,需要额外配置 module: { rules: [ { test: /\.(jpg|png|gif)$/, // 对文件类型后缀进行匹配 use: { loader: 'url-loader', // 使用url-loader对图片进行打包,如果url-loader的options没有设置limit,默认将所有静态文件全部打包成base64的字符串放到js里 options: { esModule: false, // 新版本中esModule默认为true,会导致图片的地址变为[object Module],因此这里设置为false name: '[name]_[hash].[ext]', // 输出的文件名为[原名称]_[哈希值].[原后缀] outputPath: 'images/', // 文件存储路径(output.path + 值)(物理路径, 存储路径) // 负责输出目录, 即打包后的写在磁盘的位置 } } }, ] }, output: { // filename: '[name].[contenthash].js', // contenthash,根据content(代码内容)产生的hash值,如果代码不变,contenthash就不会变,否则就会变,主要为了解决浏览器缓存因为名字不变,更新代码后不重新请求更新后文件的问题 // chunkFilename: '[name].[contenthash].chunk.js', // contenthash,根据content(代码内容)产生的hash值,如果代码不变,contenthash就不会变,否则就会变,主要为了解决浏览器缓存因为名字不变,更新代码后不重新请求更新后文件的问题 filename: '[name].js', // 打包后输出的打包文件的文件名,根据entry的chunk name作为输出文件名(如果entry有多个入口文件时必须用占位符这样设置output.filename) // filename: '[name].[chunkhash].js', // 打包后输出的打包文件的文件名,根据entry的chunk name + chunkhash(解决缓存不更新的问题)作为输出文件名(如果entry有多个入口文件时必须用占位符这样设置output.filename) // chunkFilename: '[name].chunk.js', // 入口文件走filename,其他非入口文件是index.js引入(同步引入或者异步引入)的间接js文件(非入口文件),如果打包生成的间接js文件,是走chunkFilename path: path.resolve(__dirname, 'dist'), // 指定打包后输出的打包文件在当前webpack.config.js所在文件夹的绝对路径的dist文件夹下 // path值必须是绝对路径 ,所以引入path包,__dirname代表当前webpack.config.js所在文件夹的绝对路径 // 整体路径为第一个参数+第二个参数,即__dirname + dist // 是所有输出文件的目标路径(物理路径, 存储路径); publicPath: '/' // (url 相对于 HTML 页面所在文件夹的绝对路径 + 值)给output配置全局的publicPath, // 这样各个loader打包出来的文件发布路径(引用地址)就是此全局publicPath + loader的options.outputPath // (文件引用路径就是看这个) // 是对页面引入资源的补充,比如img标签引入或者css引入等. // 千万不能设错,应该观察文件和HTML页面的存储地址位置,进行设置,否则引用时地址会错误,找不到文件 // publicPath: 'http://www.cdn.cn' // 如果,想把打包后生成的index.html作为入口文件,而打包生成的js放到服务器上如http://www.cdn.cn,那么webpack就应该这样设置 } }
重新npm run bundle打包
图片成功出现
但是发现打包生成的dist没有图片文件,这是怎么回事呢?
看一下打包生成的main.js,原来url-loader将图片转成了base64字符串,放到了main.js里
url-loader的limit
正常情况下,小图片我们为了减少http请求次数,可以将其打包进main.js里,但是如果图片过大,放到main.js反而会影响页面打开的速度,因此我们最好做一个限制,超出限制大小的图片,则将其打包到一个image文件夹里,未超出限制大小,则将图片转成base64打包进main.js里。url-loader恰好有这个功能
webpack.config.js增加url-loader的limit
rules: [ { test: /\.(jpg|png|gif)$/, // 对文件类型后缀进行匹配 use: { loader: 'url-loader', // 使用url-loader对图片进行打包,如果url-loader的options没有设置limit,默认将所有静态文件全部打包成base64的字符串放到js里 options: { esModule: false, // 新版本中esModule默认为true,会导致图片的地址变为[object Module],因此这里设置为false name: '[name]_[hash].[ext]', // 输出的文件名为[原名称]_[哈希值].[原后缀] outputPath: 'images/', // 文件存储路径(output.path + 值)(物理路径, 存储路径) // 负责输出目录, 即打包后的写在磁盘的位置 limit: 2048 // 限制当文件小于2KB的时候,就将文件转为base64存储于js中,以减少http请求次数,当文件大于2KB,则打包文件到指定目录,避免js过大 } } }, ]
重新npm run bundle打包,可以看到dist目录生成了images目录和一张图片
但是打开index.html,提示图片路径出错了
上一篇文章webpack成长指北第5章—webpack的基础配置讲过,output.publicPath是对页面引入资源的补充,比如img标签引入或者css引入等,一般来说,如果打包本地资源报404,很有可能就是publicPath没设置正确导致的,我们修改一下webpack的output.publicPath
output: { filename: '[name].[contenthash].js', // contenthash,根据content(代码内容)产生的hash值,如果代码不变,contenthash就不会变,否则就会变,主要为了解决浏览器缓存因为名字不变,更新代码后不重新请求更新后文件的问题 path: path.resolve(__dirname, 'dist'), // 指定打包后输出的打包文件在当前webpack.config.js所在文件夹的绝对路径的dist文件夹下 // path值必须是绝对路径 ,所以引入path包,__dirname代表当前webpack.config.js所在文件夹的绝对路径 // 整体路径为第一个参数+第二个参数,即__dirname + dist // 是所有输出文件的目标路径(物理路径, 存储路径); publicPath: './dist/' // (url 相对于 HTML 页面所在文件夹的绝对路径 + 值)给output配置全局的publicPath, // 这样各个loader打包出来的文件发布路径(引用地址)就是此全局publicPath + loader的options.outputPath // (文件引用路径就是看这个) // 是对页面引入资源的补充,比如img标签引入或者css引入等. // 千万不能设错,应该观察文件和HTML页面的存储地址位置,进行设置,否则引用时地址会错误,找不到文件 }
再次打包,运行成功,图片成功展示
如有问题,欢迎探讨,谢谢。