Fork me on GitHub

webpack配置

webpack 学习笔记

  • entry 打包入口
1
2
3
4
5
//单入口
entry:'./src/index.js
entry:{
app:''
}

搭建服务器 webpack-dev-server

  • 安装
1
yarn add webpack-dev-server -D
  • 使用
1
2
3
4
5
6
devServer:{
port: 3000, //端口号默认8080
open: true, //自动打开
contentBase: path.resolve(__dirname,'dist') // 指定了服务器资源的根目录,如果不写入contentBase的值,那么contentBase默认是项目的目录
host:'127.0.0.1',//主机域名
}

转化 es6 语法

  • 安装 babel-loader loader 核心模块,将 es6 转化成 es5 的插件

    1
    2
    yarn add babel-loader @babel/core @babel/preset-env @babel/plugin-proposal-class-properties @babel/plugin-transform-runtime    -D
    yarn add @babel/runtime
  • 配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
rules:[
{
test:/\.js$/,
use:{
loader: babel-loader,
options:{
presets: [
'@babe-preset-env',//es6-》es5
],
plugins:[
"@babel/plugin-proposal-decorators",//装饰器 必须放在class之前
'@babel/plugin-proposal-class-properties',// es7-es5 class
'@babel/plugin-transform-runtime' generator 运行时的
]
}
}
}
]

class 和 decorator 插件 json 写法

1
2
3
4
"plugins": [
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose" : true }]
]
  • 配置好后需要排除 node_modules,否则 warning
1
2
include:path.resolve(__dirname,'src'),
exclude: /node_modules/

使用 eslint 进行代码校验

  • 安装
1
npm install eslint-loader eslint --save-dev
  • 配置
1
2
3
4
5
6
7
8
{
test: /\.js$/,
exculde:/node_modules/,
loader: "eslint-loader",
options:{
enforce: 'pre'//在最前面校验代码 normal 普通从下到上,从左到右执行 post后置 内联loader->expose-loader
}
}
  • 在 eslint 官网,配置语法规则,下载配置文件eslintrc.json,修改配置文件名为.eslintrc.json
    Rules Configuration

引入第三方模块

  • 安装
1
2
yarn add jquery
yarn add expose-loader -D
  • 配置
    • 直接使用
1
2
import $ from 'jquery'
console.log($)
  • 暴露到全局
    1、模块中配置
1
2
3

import $ from 'expose-loader?$!jquery'
console.log(window.$)

2、webpack 中配置

1
2
3
4
5
6
7
rules:[
{
test:require.resolve('jquery),
use:'expose-loader?$'

}
]
  • 在每个模块中注入依赖
1
2
3
4
5
6
7
const webpack = require('webpack')

new webpack.ProvidePlugin({
$:'jquery'
})

直接使用$
  • 通过 cdn 引入
1
2
3
<script src="https://cdn.bootcss.com/jquery/3.3.1/jquery.js"></script>
//使用
console.log(window.$)

同时使用 cdn 和 npm,但是不打包到项目中,这个研究了一下午,这么绕,纯粹扯淡

  • 使用
1
import $ from 'jquery';
  • 配置
1
2
3
externals:{
jquery:'$'
}

图片处理

1、js 中创建图片,

1
2
3
4
import logo from './logo.png';
let image=new Image();
image.src= logo;
document.body.appendChild(image);
  • loader
1
yarn add file-loader  url-loader -D

默认会在内部生成一张图片,放到 build 目录下,并返回图片名字

2、css 中背景图片
background: url(‘./logo.png’)

3、html 中使用
loader:

1
yarn add html-withimg-loader -D

配置

1
2
3
4
{
test:/\.html$/,
loader:'html-withimg-loader'
}

使用 url-loader,小于 limit 的时候将图片打包为 base64,减少 url 请求
url-loader 内置了 file-loader,不依赖 file-loader

1
2
3
4
5
6
7
8
9
10
11
{
test: /\.(png|jpg|gif)/,
use: {
loader: 'url-loader',
options:{
limit:1024*200
}

}

}

打包文件分类

  • 设置打包后文件路径
    • 打包图片
1
2
3
4
5
6
7
8
9
10
11
{
test: /\.(png|jpg|gif)/,
use: {
loader: 'url-loader',
options:{
limit: 1024*200,
outputPath: 'img/'
}
}

}
  • 打包 css
1
2
3
new MiniCssExtractPlugin({
filename:'css/main.css'
})

同时 MiniCssExtractPlugin.loade 也需要配置 publicPath,否则 css 中的背景图片无法显示

1
2
3
4
5
6
 {
loader:MiniCssExtractPlugin.loader,
options: {
publicPath: '../'
}
},
  • 配置打包后资源的公共路径
    • 所有资源配置相同的地址
1
2
3
4
5
output:{
filename: 'bundle.js',
path: path.resolve(__dirname,'build'),
publicPath: 'http:www.baidu.com'
}
  • 只处理图片
1
2
3
4
5
6
7
8
9
10
11
{
test: /\.(png|jpg|gif)/,
use: {
loader: 'url-loader',
options:{
limit: 1024*200,
outputPath: 'img/',
publicPath: 'http:www.baidu.com',
}
}
}

打包为多页面应用

webpack.config.js

1
2
3
4
5
6
7
8
9
10
module.exports={
entry:{
home: './src/index.js',
other: './src/other.js'
},
output: {
filename:'[name].js',
path: path.resolve(__dirname, 'dist')
}
}

生成多个 html

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const htmlWebpackPlugin = require('html-webpack-plugin');
plugins:[
new htmlWebpackPlugin({
template:'./public/index.html',
filename:'home.html',
chunks:['home'],//如果一个页面包含多个js,chunks:['home','other'] title:'home',//配置html的title,<title><% html%></title>

}),
new htmlWebpackPlugin({
template:'./public/index.html',
filename:'other.html',
chunks:['other'],//如果一个页面包含多个js,chunks:['home','other']
title:'other',
})
]

配置 source-map

报错时映射到源文件

1
2
3
4
5
6
7
8
//1、源码映射,单独生成映射文件,出错标当前出错的位置 生成文件大,全
devtool:'source-map'
//2、不会产生单独的文件,但是可以显示行和列
devtool:'eval-source-map'
//3、 不会产生列,但是生成单独的映射
devtool:'cheap-module-source-map'
//4、不会产生文件,集成在打包后的文件,不会产生列
devtool: 'cheap-module-eval-source-map'

watch

监控文件的变化,即使打包
配置

1
2
3
4
5
6
watch:true
watchOptions:{
pool: 1000, //每秒询问的次数
aggregateTimeout: 500, //防抖,输入结束5秒后打包
ignored: /node_modules/, // 不要监控的文件
}

打包前清空 dist

  • 安装
1
yarn add clean-webpack-plugin -D
  • 配置
1
2
const cleanWebpackPlugin = require('clean-webpack-plugin')
new cleanWebpackPlugin()

copy-webpack-plugin

在根目录新建 doc 文件夹存放需要拷贝的文件
打包时将 webpack 拷贝到 dist 文件中

  • 安装
1
yarn add copy-webpack-plugin -D
  • 配置
1
2
3
4
const copyWebpackPlugin = require('ccopy-webpack-plugin')
new copyWebpackPlugin([
{from: 'doc',to:'./'}
])

打包代码前面都添加统一的签名

webpack 自带插件 BannerPlugin

1
new webpack.BannerPlugin('明天和意外')

webpack 跨域问题

1)请求后端

  • 配置 server.js node server
1
2
3
4
5
6
const express= require(express);
let app= express();
app.get('/api/user',(req, res)=>{
res.json({name:'略略略'})
} )
app.listen(3000)
  • 发请求
1
2
3
4
5
6
7
let xhr = new XMLHttpRequest();
//服务在3000端口,本地是8080
xhr.open("GET", '/api/user", true );
xhr.onload = function(){
console.log(xhr.response)
};
xhr.send();
  • 配置代理
1
2
3
4
5
devServer:{
proxy:{
"/api": "http://localhost:3000"
}
}

所有以/api 开头的都去访问 3000 端口

如果后端没有约定是以 api 开头的,请求之后重写 api 为空

1
2
3
4
5
6
7
8
devServer:{
proxy: {
'/api':{
target:'http://localhost:3000',
pathRewrite:{'/api' :''}
}
}
}

2)前端模拟数据

1
2
3
4
5
6
7
devServer:{
before(app){
app.get('/user',(req,res)=>{
res.json({name:'ddd'})
})
}
}

3)在服务端使用 webpack

  • 中间件
1
yarn add webpack-dev-middleware
  • server.js 配置,接口会同时配置在 server 的 3000 和 webpack 的 8080
1
2
3
4
5
6
7
8
9
10
11
12
13
14
const  express = require('express');

const app = express();
const webpack= require('webpack');
const middle = require('webpack-dev-middleware');
const config = require('./webpack.config.js');
let compiler = webpack(config);
app.use(middle(compiler));

app.use('/user', (req, res) => {
res.json({name:'ddd111'})
})

app.listen(3000)

resolve 解析第三方包

  • 只在当前文件夹内解析
1
2
3
resolve:{
modules:[path.resolve('node-modules')]
}
  • 安装 bootstrap
1
yarn add bootstrap

使用 import bootstrap from ‘bootstrap’引入的是 bootstrap.js
使用别名直接引入 bootstrap.css

1
2
3
4
5
resolve:{
modules:[path.resolve('node-modules')],
alias:{ 'bootstrap': 'bootstrap/dist/css/bootstrap.css'}

}

指定解析的文件入口顺序

1
2
mainFields:['styles','main'];
// mainFiles指定入口文件的名字,默认index.js

省略文件后缀

1
extensions:['.css','.js','.json']

定义环境变量

1
2
3
4
5
6
new webpack.DefinePlugin({
DEV: JSON.stringify('dev'), // 字符串外面再套字符串
Flag: 'true',
// EXPRESSION: JSON.stringify('1+1') //'1+1',
EXPRESSION: '1+1' //2,
})

区分不同环境

webpack.base.js
webpack.dev.js
webpack.prod.js

  • 合并 webpack 配置
1
yarn add webpack-merge -D
  • 使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//webpack.dev.js
let { smart } = require('webpack-merge');
let base = require('./webpack.base.js');
module.exports = smart(base, {
mode:'development',
devServer:{},
devtool:'source-map'
})

//```webpack.prod.js
let { smart } = require('webpack-merge');
let base = require('./webpack.base.js');
module.exports = smart(base, {
mode:'production',
minimizer:[],
plugins[]
})

noParse

1
noParse:/jquery/, //不去解析jquery中的依赖库

ignorePlugin

1
2
3
4
5
6
7
8
9
10
11
12
13
modules:{
rules:[
{
test: /\.js$/,
exclude:/node_modules/, //排除node_modules下的js文件
include:path.resolve('src'), //包含src下的文件
use:{
loader: 'babel-loader',
presets:['@babel/preset-env', '@babel/preset-resct']
}
}
]
}

忽略引入文件的内部文件

  • 安装 moment
1
yarn add moment -D
  • 使用
1
2
let r = moment().endOf('day').fromNow();
console.log(r)
  • 显示中文时间
1
moment.locale('zh-cn')

打包时忽略 moment 的语言包引入

1
new webpack.IgnorePlugin(/\.\/locale/,/moment/)
  • 手动引入中文
1
import 'moment/locale/zh-cn'

动态链接库 dllPlugin

打包不需要每次更改都需要重新打包的文件

  • 安装 React React-dom
1
yarn add React React-dom
  • React 代码
1
2
3
import React from 'React';
import { render } from 'React-dom';
render(<h1>JSX</h1>, window.root);
  • 抽离 React,React-dom 单独打包
    webpack.React.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
let path = require('path');
let webpack = require('webpack')
module.exports= {
model:'development',
entry: {
React:['React',React-dom'],
},
output:{
filename:'_dll_[name].js',//产生的文件名
path: path.resolve(__dirname, 'dist'),
library:'_dll_[name]', //打包产生的文件赋值变量名
//libraryTarget:'commonjs’ //export 默认是var,可以是 umd统一资源 this
},
plugin:[
new webpack.DllPlugin({ //打包文件的清单
name: '_dll_[name]', //name就是输出的filename名字
path: path.resolve(__dirname, 'dist', 'manifest.json')
})
]

}
  • html 中引入打包后文件
1
<script src='/_dll_React.js'></script>
  • webpack.config.js
    引用 dll 插件,引用模块的时候会先查找 dll 里面的清单找不到的时候再打包
1
2
3
new webpack.DllReferencePlugin({
manifest: path.resolve(__dirname, 'dist', 'manifest.json')
}),

打包

1
npx webpack --config webpack.React.js

多线程打包 happypack

  • 安装
1
yarn add happypack -D
  • 引入
1
import happypack from 'happypack'
  • 使用
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
modules: {
rules: [
{
test: /\.js$/,
user: 'happypack/loader?id=js'
}, {
test: /\.css$/,
user: 'happypack/loader?id=css'
}
]
}
plugins: [
new happypack({
id:js,
use: [
{
loader: 'babel-loader',
presets:['@babel/preset-env', '@babel/preset-React']
}
]
}),
new happypack({
id:css,
use: ['style-loader','css-loader'],
})
]

多页面打包抽取公共代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
optimization:{
splitChunks:{//分割代码块
cacheGroups:{//缓存组
common:{//公共的模块
chunks:'initial',//
minSize:0, //形成一个新代码块最小的体积默认30000
minChunks:2,//公共模块使用2次以上,默认一次
},
vendor:{//第三方模块
priority:1,//抽离权重,先后顺序
test:/node_modules/,
chunks:'initial',
minSize:0,
minChunks:2
}

}
}
}

懒加载

安装 js 插件@babel/plugin-syntax-dynamic-import

  • 配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
{
test:/\.js$/,
use: [
{
loader:'babel-loader',
options:{
presets:[
'@babel/preset-env',
'@babel/preset-React'
],
plugin:[
'@babel/plugin-syntax-dynamic-import'
]

}
}
]
},
  • 使用 获取资源文件
1
2
3
import('./source').then(data=>{
console.log('data',data)
})

热更新

  • 启用热更新
1
2
3
devServer:{
hot:true
}
  • 插件
1
2
3
4
plugins:[
new webpack.NamedModulesPlugin(),//打印更新的模块名d
new webpack.HotModuleReplacementPlugin()//热更新插件
]
  • 模块里面的使用
1
2
3
4
5
6
7
8
if(module.hot){
console.log(111)
module.hot.accept('./source',()=>{
console.log('文件更新了')
let str=require('./source')
console.log(str)
})
}
-------------本文结束感谢阅读-------------