webpack成神(1)
webpack 的成神配置
webpack 的基础
本地安装插件
webpack webpack-cli
npx webpack 或者 执行 node_modules 下的 bin 下的 webpack 文件
手动配置
webpack 默认的配置文件的名字,webpack.config.js 或者 webpackfile.js
手动指定 webpack 配置文件 npx webpack --config 配置文件的名字
```javascript
module.export={
mode #模式选项
#入口 entry:'打开的入口文件'
#出口 output //出口位置:{
#文件名 filename:’‘
#文件路径 path:path.resolve(\_\_dirname,'文件夹路径')
}
}
```
在本地启动一个模拟服务,安装 webpack-dev-server,
```javascript
在config 中加入配置
devServer:{
port:3000, #端口
progress:true,# 开启进度条
contentBase:'./build'# 服务开启基于的根目录
compress:true #开启GZP压缩
}
```
解析 HTML
打包 WebpackHtmlPlugin
```javascript
new WebpackHtmlPlugin({
minify: {# 进行压缩的优化选项
collapseWhitespace: true, //清除空格 折叠空行
removeAttributeQuotes: true, //清除多余引号
removeComments: true //删除注释
},
title: "tttttttt", //打包出来的文件的title名字
template: "./index.html", //要打包的html文件路径
chunks: ['index'],
hash: true,//生成hash戳 解决缓存问题
filename: "index.html", //要打包的文件名字
}),
```
解决缓存问题
加入 hash 在需要加入 hash 戳的地方加入.[hash:长度].后缀
css 的引入问题
在 webpack 加入 module
```javascript
module: {#模块
rules: [#规则 cssloader 主要解析 @import style-loader 把css插入到head标签中
#loader 希望功能专一 多个loader 是有执行顺序的 默认是从右向左执行 所以 css 处理的loader 写法是
{
test:/\.css$/,
use:[
{
loader:'style-loader'
options:{
insertAt:'top'#把生成css 标签插入到顶部 这样自定义的css 会获得高优先级
}
},
{
loader:'css-loader'
options:{}
}
]
}
]
}
```
处理 less
```javascript
{
test:/\.less$/,
use:[
{
loader:'style-loader'
options:{
insertAt:'top'#把生成css 标签插入到顶部 这样自定义的css 会获得高优先级
}
},
{
loader:'css-loader'
options:{}
},
{
loader:'less-loader'#会调用这个loader 把less 转换为CSS 其他 类似 sass scss styles 都一样类似
options:{}
}
]
}
```
其他 css 处理方式
抽离 css 样式到单一的 link 标签内 mini-css-extract-plugin ,plugin 插件的使用顺序是没有时间先后的
```javascript
#在plugins 中添加
new MiniCssExtractPlugin({
filename:'main.css'#抽离出来的css 文件名称
})
#在css 的解析模块中 使用MinicssExtrectPlugin.loader 这样就把css 单独的抽离打包出来
```
自动化 css 前缀
autoprefixer 使用这个包的前提是 css 经过 loader 处理过(postcss-loader)
```javascript
# 安装 autoprefixer 和postcss-loader
# postcss-loader 作用是在css 处理之前对css 做预处理
# autoprefixer 是对css 需要加浏览器前缀的自动加上前缀
# postcss-loader需要新建配置文件 postcss.config.js
#postcss.config.js 中
module.exports = {
plugins: [require('autoprefixer')]
}
#在 webpack.config.js 在css-loader 下面加上postcss-loader
{ loader: 'css-loader' }, {loader: 'postcss-loader'}
这样postcss-loader 会自动找postcss.config.js
```
css 的优化 css 的压缩
使用 mini-css-extrect-plugin 中说明 css 需要子集压缩 css 文件,在 mini 中右优化项
在 webpack 中加入如下配置
```javascript
optimization: { webpack 的优化项
minizer: [
new UglifyJsPlugin({#压缩js
cache: true,//开启缓存
parallel: true,//是否并发打包
sourceMap: true//压缩完的js如果是es6 编程es3 会有一个源码映射 为了更好的调试
}),
new OptimizeCSSAssetsPlugin({})
]
}
plugins:{
new MiniCssExtractPlugin({# wenpack默认在压缩js的时候调用的就是UglifyJsPlugin 而在压缩css的时候则OptimizeCSSAssetsPlugin
# 而如果使用OptimizeCSSAssetsPlugin 则必须使用UglifyJsPlugin 二者必须同时存在
filename:'[name].css',
chunkFilename;'[id].name'
})
}
```
在 webpack 中处理 js
主要依赖 babel 进行高低版本的转换 转化的 loader babel-loader babel 转换依赖的核心代码
@babel/core @babel-preset-env 进行预先编译转换
如果需要把 ES6 转换为 ES5 那么需要在 option 是、内进行配置
```javascript
{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {//babel=preset-env是进行语法版本转换的核心库所以需要对欲解析进行设置
presets:['@babel/preset-env'],//z这个就是对其经行预设 预解析 这个是预设插件的集合
plugins:['@babel/plugin-proposal-class-properties']//#对转换模块中需要的其他插件的定义 @babel/plugin-proposal-class-properties
//这个插件是对es7 中class 的转换 所有需要的插件都可以去babel 中进行搜索然后安装到Babel中
}
}
}
```
webpack 中的第三方模块
使用例如在 js 文件中引入了第三方的包 expose-loader 暴漏全局的 loader 内联的 loader 这个 loader 会把
把在内部注册的模块暴漏给 window 对象 这样一些需要加载在 window 的第三方模块就可以使用了例如 jquery。
使用方法
```javascript
#安装
npm i expose-loader
#第一种方法 在需要把变量暴漏给全局window 对象的地方
import $ from 'expose-loader?$!jquery'# 这样就挂载在全局window 对对象上了
# 第二种方法 或者 如果不想污染js 引入模块代码 可以在webpack 中配置
# 在module 模块中加入一条新的规则
{
test:require.resolve('jquery'),//皆空请求中解析出右jquery的
use:'expose-loader?$'//意思就是把jquery引用的时候编程一个$符号
}
#第三种方法 如果需要在每个模块中都注入¥符号 或者是某个插件 则需要一个webpack的注入插件
# 在webpack plugins 中添加一条
new webpack.ProvidePlugin({
$:'jquery'
})
#最后一个的区别是只是在每个模块中都注入的$ 而并未和window 绑定
# 第四种 情况 如果在页面引入的是一个cdn 的路径 而不是一个库,而在后端开发过程中右使用了这个库,那么在打包过程中就需要忽略这个库的源码
#而指向页面的cdn 路径 这个时候需要配置webpack的externals(忽略)指明这个模块是外部引入的并不需要打包
externals:{
jquery:'$'
}
```
loader 的分类
pre loader 前置 loader
普通的 loader normal
内联的 expose-loader 需要直接在代码里面使用的
后置的 post loader
图片处理
- 在 js 中创建图片来引入
```javascript
//这个时候打包会找不到img 在JS 中图片引入要写引入的路径
let image= require('./logo.png')
let img = new Image()
img.src = image
document.body.appendchild(img)
//这个时候需要安装 file-loader 作用就是 在内部生成一张图片 到build 目录下 会把图片的路径和名字返回回来 插入到引用位置
npm i file-loader
// 在webpack 中 写
{
test:/\.(png|jpg|gif)$/,
use:[
{loader:'file-loader'}
]
}
这样就可以打包图片到新的文件夹中
```
- 在 css 中 background 引入
```javascript
# 在css 中背景图片可以直接进行打包 他会把url 转换未类似于require的东西 只需要把css 文件引入到js 中
```
- 在 html 中直接 img
```javascript
# 在html 中引用图片会右路径问题
<img src="./logo.png">//这样写是死的 打包生成新的文件后 路径变换成新的
#需要新的loader html-withimg-loader
npm i html-withimg-loader//专门解析html img的路径
# 在webpack.config.js中加入
{
test:/\.html$/,
use:'html-withimg-loader'
}
```
- 处理图片的大小问题
一般情况下我们不会直接使用 file-loader 二是使用 url-loader 可以处理图片大小和路径问题,可以做一个限制,当图片小于限制的时候
使用 base64 字符串减少请求,当图片大于指定大小的时候使用 file-loader 产出
希望 css js img 按照对应的文件夹产出
```javascript
{
test:/\.(img|jpg|gif)$/,
use:{
loader:'url-loader',
options:{
limit:8192,
output:'/img/'#文件输出目录 会自动生成img 这个目录
}
}
}
# css
new MiniCssExtractPlugin({
filename:'css/main.css'
})
```
如果图片和 css 等推送到 cdn 服务器上
那么会加上域名访问,这个时候配置 publicPath
```javascript
output:{
filename:'bundle.js',
path:path.resolve(__dirname,'build')
publicPath:'http://www.aaaa.com'#当在引用资源的时候会统一加上这个值
}
#如果只有css 和图片推送到cdn js还自己的服务器那么可以只在图片和css 上单独加一个publicpath
{
test:/\.(img|jpg|gif)$/,
use:{
loader:'url-loader',
options:{
limit:8192,
output:'/img/'#文件输出目录 会自动生成img 这个目录
publicpath:'http://www.aaaa.com'
}
}
}
```
webpack 的其他配置
多页配置
适合多个界面每个界面都有自己的 js,也就是多入口
entry:{
home:'./src/index.js',//主入口
other:'./src/other.js'//其他入口
},
output:{
filename:'[name][hash:8].js',//根据js名称生成
path:path.resolve(__dirname,'dist')
}
2
3
4
5
6
7
8
多个页面生成不同的 html
有多少个页面使用插件多少次, chunks:['home']//这个和入口的 key 对应,可以对应每个页面使用某一个某块的 js
而避免每个页面都把所有 JS 全部引入的问题
entry:{
home:'./src/index.js',//主入口
other:'./src/other.js'//其他入口
},
output:{
filename:'[name][hash:8].js',//根据js名称生成
path:path.resolve(__dirname,'dist')
},
plugins:[
new HtmlWebpackPlugins({//主页面
template:'./index.html',
filename:'index.html',
chunks:['home']//这个和入口的key对应
}),
new HtmlWebpackPlugins({//第一个其他页面
template:'./other1.html',
filename:'other1.html',
chunks:['others']//这个和入口的key对应
//chunks:['others','home'] 可以两个都引用
}),
]
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
sourceMap
因为打包后的代码只有一样 而且全部被转换为低版本的代码 不知道如何调试,这个时候需要 sourcemap,源码映射,增加映射文件
# 第一种
//devtool:'source-map',//源码映射,会单独生成一个sourcemap 文件 出错了会标识当前出错的列和行 xxx。map
#第二种
devtool:'evel-source-map',//也会显示报错点 源码 但是不会单独打包出map 映射文件,会集成在文件中
#第三种
devtool:'cheap-module-source-map'//不会产生列,但是会产生一个单独的影身文件,产生后可以保留起来用来调试,并且产生的文件与源文件无关联
#第四种 不会产生文件 集成在打包后的文件中 不会产生列
devtool:'cheap-module-eval-source-map'
modules: {
rules: [{ test: /\.js$/ }
use:[{
loader:'babel-loader',
options:{
presets:['@babel/preset-env']
}
}]]
}
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
webpack 的监控打包,实时打包
# 在webpack.config.js 中增加watch 选项
watch:true, //这样就可以实时监控实时打包
watchOptions:{
poll:1000,//每秒问我1000次 合理值大概就是1000
aggregateTimeout:500, //防抖 也就是不要我在写代码的时候一直在打包,当我停止更新代码后的500毫秒后打包代码
igored:/node-modules/* // 不需要监控的文件夹
}
2
3
4
5
6
7
8
webpack 中的小插件
cleanwebpackPlugin 可以在每次输出目录之前把 dist 目录删掉 这样每次打包之后看到就是最新的目录
#安装 npm i clean-webpack-plugin -D # 引入 const CleanWebpackPlugin = require('clean-webpack-plugin') # 使用 plugins:[ new CleanWebpackPlugin('./dist')# 需要删除的打包的路径 ]
1
2
3
4
5
6
7
8copywebpackplugin 拷贝插件 如果有需要打包的其他文件 并且这写信息和数据和项目内没有关联 这些文件的打包
#安装 npm i copy-webpack-plugin -D # 引入 const CopyWebpackPlugin = require('copy-webpack-plugin') # 使用 plugins:[ new CopyWebpackPlugin([# 多个文件夹需要拷贝就传入多个 {from:'./doc', #从doc 目录下把文件拷贝到dist 目录下 to:'./'//这个就可以默认在dist 目录下 }, {from:'./yml', #yml 目录下把文件拷贝到dist 目录下 to:'./build'#拷贝到build 目录下 } ]) ]
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15bannerPlugin 版权声明插件 这个是 webpack 内部的插件
#需要先引入webpack const webpack = require('webpack') #在配置文件内部 plugins:[ new webpack.BannerPlugin('版权所有---xxx,由xxx 在那天制作')# 内部写入版权字符串,好久可以在每个打包的文件中插入这个字符串 ]
1
2
3
4
5
6
webpack 的跨域问题,
如果在开发过程中碰到服务端渲染,由于服务端启动的端口和 webpack 的端口肯定不一致,这个时候会产生跨域问题, 前端单纯向模拟数据,或者在前后端分离项目中 需要使用 nginx 反向代理资源,在正式上线的时候 html 中不是直接访问后端端口这个时候 需要使用到 webpack 代理处理跨域问题,模拟真实生产环境,把开发过程中访问到 webpack 上的端口转发到服务器接口端
# 在webpack.config.js 文件中配置
第一种使用方法
devServer:{
proxy:{
<!-- '/api':'http://localhost:3000' -->
'/api':{
target:'http://localhost:3000',
pathRewrite:{'/api':''}//把api 替换为 空字符 也就是去掉api,
}
}
}
第二种使用方法 模拟数据 ,因为webpack 内置了一个express 所以可以直接使用 express 的api
devServer:{
before(app){
app.get('/user',(req,res)=>{
res.json({name:"hahahahaha"})
})
}
}
#第三种使用方法 如果有服务端,在服务端启动webpack 端口共用
#在服务端 需要 webpack的中间件 webpack-dev-middleware
const express = require('express)
const app = express()
const webpack = require('webpack')
const webpackmiddleware = require('webpack-dev-middleware')# 可以在服务端启动webpack
const webpackConfig = require('./webpack.config.js')
const compiler = webpack(webpackConfig)
app.use(webpackmiddleware(compiler))
app.listen(3000)
#这样就在服务端启动的时候直接打包了webpack,并且启动了webpack
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
27
28
29
30
31
resolve webpack 的解析第三方包
resolve: {
modules: [path.resolve('node_modules')], //如果第三方模块在其他目录种还有 也可以加在resolve 种 可以同时写多个
mainFilelds:['style':main]//入口的字段 对应第三方模块包 package。json 中的字段
extensions:['.js','.css','.json']//拓展名 ,标记如果找不就添加拓展名,按集合内拓展名遍历
mainfiles:[]//入口的文件的名字 如果没有写 指向index。js
alias:{
bootstrap:'bootstarp/dist/css/bootstarp.css'//通过别名指定资源路径的短命名,
}
}
# 在引入模块的地方可以直接写
import 'bootstarp' # 不会指向js 二是指向上面别名内的css
2
3
4
5
6
7
8
9
10
11