加载非 JS 文件
webpack 最出色的功能之一就是,除了 JavaScript,还可以通过 loader 引入任何其他类型的文件
加载 CSS 文件
- 第一步: 安装 css 和 style 模块解析的依赖
style-loader
和css-loader
npm install --save-dev style-loader css-loader
- 第二步: 添加 css 解析的 loader
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
};
css-loader
: 辅助解析 js 中的import './main.css'
style-loader
: 把 js 中引入的 css 内容 注入到 html 标签中,并添加 style 标签.依赖css-loader
你可以在依赖于此样式的 js 文件中 导入样式文件,比如:import './style.css'。现在,当该 js 模块运行时,含有 CSS 字符串的
<style>
标签,将被插入到 html 文件的<head>
中。
- 第三步: 编写 css 文件和修改 js 文件
在 src 目录中添加 style.css
文件
webpack-demo
|- package.json
|- webpack.config.js
|- /dist
|- bundle.js
|- index.html
|- /src
+ |- style.css
|- index.js
|- /node_modules
src/style.css
.hello {
color: red;
}
修改 js 文件
import _ from 'lodash';
+ import './style.css';
function createDomElement() {
let dom = document.createElement('div');
dom.innerHTML = _.join(['aicoder', '.com', ' wow'], '');
+ dom.className = 'hello';
return dom;
}
document.body.appendChild(createDomElement());
最后重新打开 dist 目录下的 index.html 看一下文字是否变成了红色的了。
module 配置补充
模块(module): 这些选项决定了如何处理项目中的不同类型的模块。
webpack 模块可以支持如下:
- ES2015 import 语句
- CommonJS require() 语句
- AMD define 和 require 语句
- css/sass/less 文件中的 @import 语句。
- 样式
(url(...))
或 HTML 文件(<img src=...>)
中的图片链接(image url)
module.noParse
值的类型: RegExp | [RegExp] | function
防止 webpack 解析那些任何与给定正则表达式相匹配的文件。忽略的文件中不应该含有 import, require, define 的调用,或任何其他导入机制。忽略大型的 library 可以提高构建性能。
module.exports = {
mode: 'devleopment',
entry: './src/index.js',
...
module: {
noParse: /jquery|lodash/,
// 从 webpack 3.0.0 开始,可以使用函数,如下所示
// noParse: function(content) {
// return /jquery|lodash/.test(content);
// }
}
...
};
module.rules
创建模块时,匹配请求的规则数组。这些规则能够修改模块的创建方式。这些规则能够对模块(module) 应用 loader,或者修改解析器(parser)。
module.exports = {
...
module: {
noParse: /jquery|lodash/,
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
...
};
module Rule
- Rule 条件详解
- 字符串:匹配输入必须以提供的字符串开始。是的。目录绝对路径或文件绝对路径。
- 正则表达式:test 输入值。
- 函数:调用输入的函数,必须返回一个真值(truthy value) 以匹配。
- 条件数组:至少一个匹配条件。
- 对象:匹配所有属性。每个属性都有一个定义行为。
Rule.test
- { test: Condition }:匹配特定条件。一般是提供一个正则表达式或正则表达式的数组,但这不是强制的。
module.exports = {
...
module: {
rules: [
{
test: /\.css$/,
use: ['style-loader', 'css-loader']
}
]
}
...
};
其他的条件比如:
{ include: Condition }
:匹配特定条件。一般是提供一个字符串或者字符串数组,但这不是强制的。{ exclude: Condition }
:排除特定条件。一般是提供一个字符串或字符串数组,但这不是强制的。{ and: [Condition] }
:必须匹配数组中的所有条件{ or: [Condition] }
:匹配数组中任何一个条件{ not: [Condition] }
:必须排除这个条件
module.exports = {
...
module: {
rules: [
{
test: /\.css$/,
include: [
path.resolve(__dirname, "app/styles"),
path.resolve(__dirname, "vendor/styles")
],
use: ['style-loader', 'css-loader']
}
]
}
...
};
Rule.use
应用于模块指定使用一个 loader。
Loaders can be chained by passing multiple loaders, which will be applied from right to left (last to first configured).
加载器可以链式传递,从右向左进行应用到模块上。
use: [
'style-loader',
{
loader: 'css-loader'
},
{
loader: 'less-loader',
options: {
noIeCompat: true
}
}
];
传递字符串(如:use: [ "style-loader" ])是 loader 属性的简写方式(如:use: [ { loader: "style-loader "} ])。
加载 Sass 文件
加载 Sass 需要 sass-loader
。
安装
npm install sass-loader node-sass webpack --save-dev
使用:
// webpack.config.js
module.exports = {
...
module: {
rules: [{
test: /\.scss$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader"
}, {
loader: "sass-loader"
}]
}]
}
};
为 sass 文件注入内容:
如果你要将 Sass 代码放在实际的入口文件(entry file) 之前,可以设置 data 选项。此时 sass-loader 不会覆盖 data 选项,只会将它拼接在入口文件的内容之前。
{
loader: "sass-loader",
options: {
data: "$env: " + process.env.NODE_ENV + ";"
}
}
注意:由于代码注入, 会破坏整个入口文件的 source map。 通常一个简单的解决方案是,多个 Sass 文件入口。
创建 Source Map
css-loader
和 sass-loader
都可以通过该 options 设置启用 sourcemap。
// webpack.config.js
module.exports = {
...
module: {
rules: [{
test: /\.scss$/,
use: [{
loader: "style-loader"
}, {
loader: "css-loader",
options: {
sourceMap: true
}
}, {
loader: "sass-loader",
options: {
sourceMap: true
}
}]
}]
}
};
PostCSS 处理 loader(附带:添加 css3 前缀)
PostCSS 是一个 CSS 的预处理工具,可以帮助我们:给 CSS3 的属性添加前缀,样式格式校验(stylelint),提前使用 css 的新特性比如:表格布局,更重要的是可以实现 CSS 的模块化,防止 CSS 样式冲突。
我们常用的就是使用 PostCSS 进行添加前缀,以此为例:
安装
npm i -D postcss-loader
npm install autoprefixer --save-dev
# 以下可以不用安装
# cssnext 可以让你写 CSS4 的语言,并能配合 autoprefixer 进行浏览器兼容的不全,而且还支持嵌套语法
$ npm install postcss-cssnext --save-dev
# 类似 scss 的语法,实际上如果只是想用嵌套的话有 cssnext 就够了
$ npm install precss --save-dev
# 在 @import css 文件的时候让 webpack 监听并编译
$ npm install postcss-import --save-dev
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, './dist')
},
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
sourceMap: true
}
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
sourceMap: true,
plugins: loader => [
require('autoprefixer')({ browsers: ['> 0.15% in CN'] }) // 添加前缀
]
}
},
{
loader: 'sass-loader',
options: {
sourceMap: true
}
}
]
}
]
}
};
样式表抽离成专门的单独文件并且设置版本号
首先以下的 css 的处理我们都把 mode 设置为 production
。
webpack4 开始使用: mini-css-extract-plugin
插件, 1-3 的版本可以用: extract-text-webpack-plugin
抽取了样式,就不能再用
style-loader
注入到 html 中了。
npm install --save-dev mini-css-extract-plugin
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const devMode = process.env.NODE_ENV !== 'production'; // 判断当前环境是开发环境还是 部署环境,主要是 mode 属性的设置值。
module.exports = {
mode: 'development',
entry: './src/index.js',
output: {
filename: 'main.js',
path: path.resolve(__dirname, './dist')
},
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'sass-loader'
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: devMode ? '[name].css' : '[name].[hash].css', // 设置最终输出的文件名
chunkFilename: devMode ? '[id].css' : '[id].[hash].css'
})
]
};
再次运行打包:
在 dist 目录中已经把 css 抽取到单独的一个 css 文件中了。修改 html,引入此 css 就能看到结果了。
压缩 CSS
webpack5 貌似会内置 css 的压缩,webpack4 可以自己设置一个插件即可。
压缩 css 插件: optimize-css-assets-webpack-plugin
安装
npm i -D optimize-css-assets-webpack-plugin
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const autoprefixer = require('autoprefixer');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'main.[hash].js',
path: path.resolve(__dirname, './dist')
},
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader'
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: loader => [autoprefixer({ browsers: ['> 0.15% in CN'] })]
}
},
{
loader: 'sass-loader'
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name][hash].css',
chunkFilename: '[id][hash].css'
})
],
optimization: {
minimizer: [new OptimizeCSSAssetsPlugin({})]
}
};
JS 压缩
压缩需要一个插件: uglifyjs-webpack-plugin
, 此插件需要一个前提就是: mode: 'production'
.
安装
npm i -D uglifyjs-webpack-plugin
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const autoprefixer = require('autoprefixer');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'main.[hash].js',
path: path.resolve(__dirname, './dist')
},
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader'
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: loader => [autoprefixer({ browsers: ['> 0.15% in CN'] })]
}
},
{
loader: 'sass-loader'
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name][hash].css',
chunkFilename: '[id][hash].css'
})
],
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true // set to true if you want JS source maps
}),
new OptimizeCSSAssetsPlugin({})
]
}
};
解决 CSS 文件或者 JS 文件名字哈希变化的问题
HtmlWebpackPlugin
插件,可以把打包后的 CSS 或者 JS 文件引用直接注入到 HTML 模板中,这样就不用每次手动修改文件引用了。
安装
npm install --save-dev html-webpack-plugin
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const autoprefixer = require('autoprefixer');
module.exports = {
mode: 'production',
entry: './src/index.js',
output: {
filename: 'main.[hash].js',
path: path.resolve(__dirname, './dist')
},
module: {
rules: [
{
test: /\.(sa|sc|c)ss$/,
use: [
MiniCssExtractPlugin.loader,
{
loader: 'css-loader'
},
{
loader: 'postcss-loader',
options: {
ident: 'postcss',
plugins: loader => [autoprefixer({ browsers: ['> 0.15% in CN'] })]
}
},
{
loader: 'sass-loader'
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name][hash].css',
chunkFilename: '[id][hash].css'
}),
new HtmlWebpackPlugin({
title: 'AICODER 全栈线下实习', // 默认值:Webpack App
filename: 'main.html', // 默认值: 'index.html'
template: path.resolve(__dirname, 'src/index.html'),
minify: {
collapseWhitespace: true,
removeComments: true,
removeAttributeQuotes: true // 移除属性的引号
}
})
],
optimization: {
minimizer: [
new UglifyJsPlugin({
cache: true,
parallel: true,
sourceMap: true // set to true if you want JS source maps
}),
new OptimizeCSSAssetsPlugin({})
]
}
};
清理 dist 目录
每次构建,我们的 /dist
文件夹都会保存生成的文件,然后就会非常杂乱。
通常,在每次构建前清理 /dist
文件夹,是比较推荐的做法
clean-webpack-plugin
是一个比较普及的管理插件,让我们安装和配置下。
npm install clean-webpack-plugin --save-dev
webpack.config.js
const path = require('path');
....
+ const CleanWebpackPlugin = require('clean-webpack-plugin');
module.exports = {
entry: {
app: './src/index.js',
print: './src/print.js'
},
plugins: [
+ new CleanWebpackPlugin()
...
],
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
}
...
};
现在执行 npm run build
,再检查 /dist
文件夹。如果一切顺利,你现在应该不会再看到旧的文件,只有构建后生成的文件!
由于最新版本变化 @2.0.1之前的写法已经不能使用:
new CleanWebpackPlugin(['/dist'])
。 官方文档地址: https://www.npmjs.com/package/clean-webpack-plugin 可以直接设置一个对象参考:new CleanWebpackPlugin({cleanOnceBeforeBuildPatterns: ['**/*', '!static-files*']})
加载图片与图片优化
在 css 文件或者 sass 文件中添加如下代码
$red: #900;
$size: 20px;
.box {
height: 30px*2;
font-size: $size;
transform: translate3d( 0, 0, 0 );
+ background: url('../static/1.jpeg')
}
运行打包发现如下错误:
ERROR in ./src/static/1.jpeg 1:0
Module parse failed: Unexpected character '�' (1:0)
You may need an appropriate loader to handle this file type.
解决方案: file-loader
处理文件的导入
npm install --save-dev file-loader
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
+ {
+ test: /\.(png|svg|jpg|gif)$/,
+ use: [
+ 'file-loader'
+ ]
+ }
]
}
};
此时运行打包,发现 dist 目录多了一个图片文件,另外报错不再出现。
那更进一步,图片如何进行优化呢?
image-webpack-loader
可以帮助我们对图片进行压缩和优化。
npm install image-webpack-loader --save-dev
使用:webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|svg|jpg|gif|jpeg|ico)$/,
use: [
'file-loader',
+ {
+ loader: 'image-webpack-loader',
+ options: {
+ mozjpeg: {
+ progressive: true,
+ quality: 65
+ },
+ optipng: {
+ enabled: false,
+ },
+ pngquant: {
+ quality: '65-90',
+ speed: 4
+ },
+ gifsicle: {
+ interlaced: false,
+ },
+ webp: {
+ quality: 75
+ }
+ }
+ },
]
}
]
}
};
此时在运行 webpack,发现会 生成的图片的大小会被压缩很多。
更进一步处理图片成 base64
url-loader
功能类似于 file-loader,可以把 url 地址对应的文件,打包成 base64 的 DataURL,提高访问的效率。
如何使用:
npm install --save-dev url-loader
webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.(png|svg|jpg|gif|jpeg|ico|woff|woff2|eot|ttf|otf)$/,
use: [
{
loader: 'url-loader', // 根据图片大小,把图片优化成 base64
options: {
limit: 10000
}
},
{
loader: 'image-webpack-loader', // 先进行图片优化
options: {
mozjpeg: {
progressive: true,
quality: 65
},
optipng: {
enabled: false
},
pngquant: {
quality: '65-90',
speed: 4
},
gifsicle: {
interlaced: false
},
webp: {
quality: 75
}
}
}
]
}
]
}
};
字体的处理(同图片)
由于 css 中可能引用到自定义的字体,处理也是跟图片一致。
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(png|svg|jpg|gif)$/,
use: [
'file-loader'
]
},
+ {
+ test: /\.(woff|woff2|eot|ttf|otf)$/,
+ use: [
+ 'file-loader'
+ ]
+ }
]
}
};
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论