默认状况下,webpack 只处理 JS 文件。若是要处理其余文件,webpack 须要配置 loaders 对文件进行预处理,这样 webpack 就能处理任意静态资源。 处理静态资源的经常使用 webpack loaders 分别有 file-loader
、 url-loader
、 css-loader
、 style-loader
,下面我将结合实例分析这些 loaders 的使用。javascript
咱们的 webpack 项目目录以下所示,静态资源包括图片和字体,放在 src/assets 目录下css
scr/index.js
文件,打包后输出到 dist 文件夹下,JS 文件最后打包到
dist/js/bundle.js
中
// webpack.config.js
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
mode: 'none',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/bundle.js',
},
plugins: [
new CleanWebpackPlugin() // 为了测试方便,咱们使用 CleanWebpackPlugin 在下次打包前清除以前的打包文件
]
};
// src/index.js
import './style.css'
// src/style.css
#app {
font-family: 'BalsamiqSans';
width: 100vw;
height: 100vh;
}
复制代码
这时候控制台运行打包指令 npm run build
,报错,报错信息以下html
ERROR in ./src/style.css
Module parse failed: Unexpected character '@' (1:0)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file
复制代码
就如一开始说的,默认状况下 webpack 只打包 JS 文件,而咱们的入口文件不单单有 JS 文件,还包括 css 文件,因而 webpack 打包报错了。vue
• style-loader 将 css 注入到 DOM 中,style-loader 须要和 css-loader 一块儿使用java
• css-loader 用来解析 @import 与 url() ,解析方式如同 import / require()webpack
咱们完善 webpack 的配置:git
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
mode: 'none',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/bundle.js',
},
module: {
rules: [
{
test: /\.css$/i,
use: ['style-loader', 'css-loader'],
},
],
},
plugins: [
new CleanWebpackPlugin(),
]
};
复制代码
这时候打包成功没有报错,可是你会发现,打包后只有一个 bundle.js
文件,css 代码也注入进了 bundle.js
文件中。咱们能够经过 MiniCssExtractPlugin
这个 plugin 将 CSS 提取到单独的文件中。请注意, MiniCssExtractPlugin.loader
与 style-loader
会冲突,当二者同时存在时,会报错 document is not defined
github
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
mode: 'none',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/bundle.js',
},
module: {
rules: [
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: 'css/[name].css',
})
]
};
复制代码
成功的打包出了 JS 文件与 CSS 文件,而且以想要的文件路径输出了web
• file-loader 用来处理静态资源,例如字体、图片等等,将资源注入到 webpack 中,而且解析资源的相互依赖npm
• url-loader 功能与 file-loader 相似,而且能够设置文件大小。当资源小于限制时,可以返回一个 DataURL
,也就是以 base64 编码的形式注入到文件中。简单来说就是将图片数据翻译成一串字符,把这串字符打包进文件中,这样引入文件就能访问到图片了
项目中准备了字体资源与图片资源,进一步更新 webpack 的配置:
// src/style.css
@font-face {
font-family: 'BalsamiqSans';
src: url('./assets/fonts/BalsamiqSans-Bold.ttf');
}
#app {
font-family: 'BalsamiqSans';
background: url('./assets/image/mai.png');
width: 100vw;
height: 100vh;
}
复制代码
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
mode: 'none',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/bundle.js',
},
module: {
rules: [
{
test: /\.(png|jpe?g|gif)$/i,
loader: 'url-loader',
options: {
name: '[name].[ext]',
limit: 8900,
outputPath: 'img'
},
},
{
test: /\.(woff|woff2|eot|ttf|otf|)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts'
},
},
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, 'css-loader'],
},
],
},
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: 'css/[name].css',
})
]
};
复制代码
如预期同样,咱们成功打包出了 JS 文件与静态资源文件。
<!DOCTYPE html>
<head>
<title> webpack-demos </title>
<link rel="stylesheet" type="text/css" href="./dist/css/main.css">
</head>
<body>
<div id="app">
hello world
<script src="./dist/js/bundle.js"></script>
</div>
</body>
复制代码
很不幸,打包后的资源路径并无找到
dist/img/mai.png
,而 css 引入的路径是
dist/css/img/mai.png
,路径不对,资源就找不到了。
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
mode: 'none',
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'js/bundle.js',
},
module: {
rules: [
{
test: /\.(png|jpe?g|gif)$/i,
loader: 'url-loader',
options: {
name: '[name].[ext]',
limit: 8900,
outputPath: 'img'
},
},
{
test: /\.(woff|woff2|eot|ttf|otf|)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: 'fonts'
},
},
{
test: /\.css$/i,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
publicPath: '../', // css 多了一层
}
},
'css-loader'],
},
],
},
plugins: [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: 'css/[name].css',
})
]
};
复制代码
这时候,打包后的静态资源配置路径引用正常了。
@font-face {
font-family: 'BalsamiqSans';
src: url(../fonts/BalsamiqSans-Bold.ttf);
}
#app {
font-family: 'BalsamiqSans';
background: url(../img/mai.png);
width: 100vw;
height: 100vh;
}
复制代码
至此,使用 webpack 成功编译了 JS 文件,图片字体等资源文件,而且分析处理了静态资源打包路径的问题。看到这里你觉得本文结束了,其实并无。 在 Vue 项目中,静态资源能够放置在根目录的 public
文件夹下、 src/assets
文件夹下,放置在这两个路径下有什么差异呢?
webpack 是如何处理静态资源的?在前面的篇幅中,咱们已经介绍了 loaders 处理静态资源。Vue 项目中, template 和 css 分别会被 vue-loader 与 css-loader 解析。例如 <img src="./logo.png" />
与 background: url(./logo.png)
,"./logo.png"
是一个相对资源路径,将由 Webpack 解析为模块依赖。logo.png 不是 JavaScript,看成为一个模块依赖时,咱们须要使用 url-loader 与 file-loader 进行处理。因为这些资源在构建过程当中可能被内联/复制/重命名,因此它们能够做为源代码的一部分。所以建议将资源文件放在 src 目录中与其余源文件一块儿。其实没必要专门放在 src/assets
,能够是基于 模块/组件 的方式放置资源文件。例如,能够在每一个放置组件的目录中存放静态资源。 放置在 public 目录下的文件不会被 webpack 处理,它们会直接被复制到最终目录(默认是 dist/static
)下。必须使用绝对路径引用这些文件。
webpack 是打包模块化工具,在 webpack 里一切文件都是模块。本文介绍了经过 loaders 解析文件,了解了经过 file-loader
、 url-loader
、 css-loader
、 style-loader
一步步的处理静态资源。比较 Vue 项目中放置静态资源的两处区别,放置在 src/assets
下的资源在构建的时候会被 webpack 打包到最终输出文件,适合放置本项目的资源文件。public 下的文件在构建的时候不会被 webpack 处理,将被直接拷贝到最终路径并引用,因此适合放置一些第三方类库文件。