一、Webpack基本配置及使用
1、安装本地Webpack
webapck webpack-cli -D
// -D 表示上线不需要打这个包
// 初始化一下,记录安装的依赖
yarn init -y
// 5.2支持的npx语法可以直接执行webpack
// 默认去找node_modules下面的bin文件里面的webpack.cmd
npx webpack
2、 Webpack可以0配置
打包工具 -> 输出后的结果(js模块)
打包 -> 支持js模块化
// 执行这行命令,即可打包出一个main.js文件
npx webpack
提示需要配置mode
3、手动配置Webpack
1. 简单示例
默认配置文件的名字:webpack.config.js
// webpack 是 node 写出来的 所以要用node的写法来运行
const path = require('path');
// 这是一个导出的配置文件
module.exports = {
mode: 'development', // 模式(两种):production development
entry: './src/index.js', // 入口
output: { // 出口
filename: 'bundle.js', // 打包后的文件名
path: path.resolve(__dirname, 'dist') // 路径(必须是一个绝对路径),__dirname不加也可以
}
}
// 结果:会在根目录下有一个 dist/bundle.js 文件
// 可以在浏览器环境中运行即可
简易示例文件
// src/index.js
let str = require('./a.js');
console.log(str);
// src/a.js
module.exports = 'hello';
打包后的结果
// dist/bundle.js
(() => {
var __webpack_modules__ = {
"./src/a.js": // key -> 模块的路径
(module) => { // value -> 函数
eval(
"module.exports = 'hello'\n\n//# sourceURL=webpack://practise/./src/a.js?"
);
},
"./src/index.js":
(
__unused_webpack_module,
__unused_webpack_exports,
__webpack_require__
) => {
eval(
'let str = __webpack_require__("./src/a.js")\r\n\r\nconsole.log(str)\n\n//# sourceURL=webpack://practise/./src/index.js?'
);
},
};
// 定义了一个缓存[如果模块加载完了,不需要再次加载,从缓存中取出即可]
var __webpack_module_cache__ = {};
// 配置实现require方法(因为require无法在浏览器中运行)
function __webpack_require__(moduleId) {
var cachedModule = __webpack_module_cache__[moduleId];
// 检查模块在不在缓存中,如果在缓存中,直接返回模块
if (cachedModule !== undefined) {
return cachedModule.exports;
}
// 安装一个模块[key: Object]
var module = (__webpack_module_cache__[moduleId] = {
exports: {},
});
// 通过key找到对应函数并执行
__webpack_modules__[moduleId](module, module.exports, __webpack_require__);
// 返回对应的module.exports即可
return module.exports;
}
var __webpack_exports__ = __webpack_require__("./src/index.js"); // './src/index.js': 入口模块
})();
2. 修改配置文件名
如果想要将配置文件名修改,如:webpack.config.my.js ,此时打包抛出异常
但是我们希望可以找到我们的配置文件。可以这样做:
npx webpack --config webpack.config.my.js
但是为了更方便,我们可以在 package.json
中进行配置:
{
//...
"scripts": {
"build": "webpack --config webpack.config.my.js"
}
//...
}
执行 npm run build
或yarn build
即可,其他类似。
但是下面这样写是需要注意的:
"scripts": {
"build": "webpack"
}
// 它并不是一个参数,不会识别config后面的内容
npm run build --config webpack.config.my.js
yarn build --config webpack.config.my.js // yarn命令是可以的
// 如果一定要这样写,可以使用下面这种方式
npm run build -- --config webpack.config.my.js
3. 本地开发服务(通过ip访问)[webpack-dev-server]
webpack-dev-server
// 可通过 npx webpack-dev-server 开启,也可配置脚本
// package.json
"scripts": {
"dev": "webpack-dev-server"
}
// webpack.config.js
module.exports = {
// ...
devServer: { // 开发服务器的配置
port: 3000, // 端口号配置
progress: true, // 可以看到打包进度条
contentBase: './dist', // 指向打包目录,希望以这个目录作为静态服务
compress: true // 启动gzip压缩
}
// ...
}
由于高版本的 webpack 与 webpack-dev-server 的兼容问题,如果不成功,可以修改脚本如下:
// package.json
"scripts": {
"dev": "webpack serve"
}
4. 使用模板自动插入脚本[html-webpack-plugin]
html-webpack-plugin
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 这是一个类
module.exports = {
// ...
output: { // 出口
filename: 'bundle.[hash].js', // 打包后的文件名,这里也加个hash避免缓存
// filename: 'bundle.[hash:8].js', // 打包后的文件名,这里也加个hash避免缓存:hash只要8位
path: path.resolve(__dirname, 'dist') // 路径(必须是一个绝对路径),__dirname不加也可以
},
plugins: [ // 数组:放着所有的webpack插件
new HtmlWebpackPlugin({
template: './src/index.html', // 模板
filename: 'index.html', // 打包后的文件名
minify: {
removeAttributeQuotes: true, // 删除属性双引号
collapseWhitespace: true // 折叠空行,变成一行
},
hash: true // 避免缓存问题,加上hash戳
})
]
// ...
}
5. 样式处理
Webpack默认只支持 JS 模块,所以对于 CSS ,需要特殊处理。
yarn add css-loader style-loader -D
yarn add less less-loader -D
...
// webpack.config.js
module.exports = {
// ...
module: { // 模块
rules: [ // 规则
{
// css-loader: 解析 @import 这种语法的
// style-loader: 把css插入到head的标签中
// loader特点:希望单一
// loader的用法:字符串只用一个loader
// 多个loader需要数组
// loader的顺序:默认从右向左、从下到上执行
// loader还可以写成对象的形式
test: /\.css$/,
use: [
{
loader: 'style-loader',
options: {
// insertAt: 'top' // css的样式插入到顶部,避免head中的style被覆盖
// insertAt 已废弃
insert: () => {
}
}
},
'css-loader'
]
},
{
// 处理less文件
// 还有 sass stylus, 类似的处理方式
// sass -> node-sass sass-loader
// stylus -> stylus-loader
test: /\.less$/,
use: [
{
loader: 'style-loader',
options: {
// insertAt: 'top' // css的样式插入到顶部,避免head中的style被覆盖
// insertAt 已废弃
insert: () => {
}
}
},
'css-loader', // 解析 @import 这种语法的
'less-loader' // less -> css
]
}
]
}
// ...
}
1. CSS抽离成单独的文件
mini-css-extract-plugin
yarn add mini-css-extract-plugin -D
// webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = {
plugins: [ // 数组:放着所有的webpack插件
new MiniCssExtractPlugin({
filename: 'main.css' // 抽离css的文件名
})
],
module: { // 模块
rules: [ // 规则
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader'
]
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader', // 解析 @import 这种语法的
'less-loader' // less -> css
]
}
]
}
}
2. 自动添加浏览器前缀
yarn add postcss-loader autoprefixer -D
配置如下:
// webpack.config.js
module.exports = {
module: {
rules: [
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
},
{
test: /\.less$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader',
'less-loader'
]
}
]
}
}
但是我们要告诉webpack我们要使用 autoprefixer
, 所以需要在根目录(webpack.config.js 同级目录)新建一个 postcss.config.js
文件:
// postcss.config.js
module.exports = {
plugins: [
require('autoprefixer')
]
}
如果以上未生效,在 package.json
文件中增加如下配置:
// package.json
{
// ...
"browserslist": [
"last 2 versions",
"> 1%",
"iOS 7",
"last 3 iOS versions"
]
// ...
}
3. CSS 压缩
optimize-css-assets-webpack-plugin
配置如下:
// webpack.config.js
module.exports = {
// ...
optimization: { // 优化项
minimizer: [
new OptimizeCssAssetsWebpackPlugin()
]
}
// ...
}
但是,使用了这个插件,会导致 js 不会被压缩了,所以必须配合使用另外一个插件:
uglifyjs-webpack-plugin
// webpack.config.js
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
module.exports = {
// ...
optimization: { // 优化项
minimizer: [
new UglifyjsWebpackPlugin({
cache: true, // 是否使用缓存
parallel: true, // 是否是并发打包,可以同时打多个
sourceMap: true // 压缩完js,ES6变为ES6,需要一个源码映射
}),
new OptimizeCssAssetsWebpackPlugin()
]
},
// ...
}
6. 转换ES6语法
Babel
1. 基础语法
yarn add babel-loader @babel/core @babel/preset-env -D
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader', // 用babel-loader需要把es6转换为es5
options: {
presets: [
'@babel/preset-env' // 把es6转换为es5的模块
]
}
}
}
]
}
// ...
}
2. class
yarn add @babel/plugin-proposal-class-properties -D
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader', // 用babel-loader需要把es6转换为es5
options: {
presets: [
'@babel/preset-env' // 把es6转换为es5的模块
],
plugins: [
'@babel/plugin-proposal-class-properties'
]
}
}
}
]
}
// ...
}
3. 装饰器
yarn add @babel/plugin-proposal-decorators -D
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader', // 用babel-loader需要把es6转换为es5
options: {
presets: [
'@babel/preset-env' // 把es6转换为es5的模块
],
plugins: [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }]
]
}
}
}
]
}
// ...
}
4. JS语法及校验
代码运行时的一个包。
1. generator、promise 等的处理
yarn add @babel/plugin-transform-runtime -D
yarn add @babel/runtime
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/,
use: {
loader: 'babel-loader', // 用babel-loader需要把es6转换为es5
options: {
presets: [
'@babel/preset-env' // 把es6转换为es5的模块
],
plugins: [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }],
"@babel/plugin-transform-runtime"
]
}
},
include: path.resolve(__dirname, 'src'), // 包括,只要这个目录下的
exclude: /node_modules/ // 排除这个目录下面的
}
]
}
// ...
}
2. 实例方法不会被解析的处理
如 includes。
yarn add @babel/polyfill
3. JS语法校验
ESLint
yarn add eslint eslint-loader -D
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.js$/, // 可以同时写多个
use: {
loader: 'eslint-loader',
options: {
enforce: 'pre' // previous 强制在其他的loader之前执行
}
}
},
{
test: /\.js$/,
// ...
}
]
}
// ...
}
7. 全局变量的引入(三种方式)
1. expose-loader
2. ProvidePlugin
3. 引入不打包(externals)
expose-loader
暴露全局的loader 内联的loader
yarn add expose-loader
用法:
// 1、 内联的方式
import $ from 'expose-loader?$!jquery'
console.log(window.$)
// 2、配置到webpack.config.js中的方式,并且引入使用
import $ from 'jquery'
// ----
module.exports = {
// ...
module: {
rules: [
{
test: require.resolve('jquery'),
use: 'expose-loader?$'
}
]
}
// ...
}
// 3、配置到webpack.config.js中的方式
// webpack.config.js
const webpack = require('webpack');
module.exports = {
// ...
plugins: [
new webpack.ProvidePlugin({ // 在每个模块中都注入 $。 [但是这样 window.$ 拿不到]
$: 'jquery'
})
]
// ...
}
注意
externals
// webpack.config.js
const webpack = require('webpack');
module.exports = {
// ...
externals: { // 意义:这个模块是外部引入的,不需要打包
jquery: '$'
}
// ...
}
8. 图片处理
1. 在JS中创建图片引入(new Image())
yarn add file-loader -D
file-loader 默认会在内部生成一张图片到打包后的目录下,把生成的图片的名字返回回来
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.(jpg|png|gif|jpeg)$/,
use: 'file-loader'
}
]
}
// ...
}
2. 在CSS中引入(background('url'))
css-loader 已支持
3. 在html中引入(
)
yarn add html-withimg-loader -D
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.html$/,
use: 'html-withimg-loader'
}
]
}
// ...
}
4. base64转换图片
当图片大于某个限制大小时,使用file-loader产出一个文件。但是小于这个限制值的时候,可以用base64来转化。
可以不用发起http请求去加载图片。
yarn add url-loader -D
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.(jpg|png|gif|jpeg)$/,
use: {
loader: 'url-loader',
options: {
esModule: false,
limit: 100 * 1024 // 图片小于100k,就使用base64,否则用file-loader产生真实的图片
}
}
}
]
}
// ...
}
9. 打包文件分类
1. 图片目录
// webpack.config.js
module.exports = {
// ...
module: {
rules: [
{
test: /\.(jpg|png|gif|jpeg)$/,
use: {
loader: 'url-loader',
options: {
esModule: false,
limit: 1,
outputPath: 'img/' // 打包到打包路径下的 img 目录中
}
}
}
]
}
// ...
}
但是引用是希望引用域名下这个目录对应的文件:
// webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin'); // 这是一个类
module.exports = {
// ...
output: { // 出口
filename: 'bundle.[hash:8].js',
path: path.resolve(__dirname, 'dist'),
publicPath: 'http://127.0.0.1:5500/dist' // 加这样一个域名
}
// ...
}
但是只想给图片加上这个域名,就可以这样做:
// webpack.config.js
module.exports = {
// ...
output: { // 出口
filename: 'bundle.[hash:8].js',
path: path.resolve(__dirname, 'dist')
}
// ...
module: {
rules: [
{
test: /\.(jpg|png|gif|jpeg)$/,
use: {
loader: 'url-loader',
options: {
esModule: false,
limit: 1,
outputPath: 'img/',
// 加这样一个域名,并且需要拼接上上面的输出目录
publicPath: 'http://127.0.0.1:5500/dist/img'
}
}
}
]
}
// ...
}
2. 样式目录
// webpack.config.js
module.exports = {
// ...
plugins: [ // 数组:放着所有的webpack插件
new MiniCssExtractPlugin({
filename: 'css/main.css'
})
]
// ...
}