webpack成神(1)


2019-3-25 webpack

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')
    }
1
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'] 可以两个都引用
        })]
1
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']
    }
}]]
}
1
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/* // 不需要监控的文件夹
}
1
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
    8
  • copywebpackplugin 拷贝插件 如果有需要打包的其他文件 并且这写信息和数据和项目内没有关联 这些文件的打包

    #安装
    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
    15
  • bannerPlugin 版权声明插件 这个是 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
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
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
1
2
3
4
5
6
7
8
9
10
11