24 个实例入门并控制「Webpack4」(二)

24 个实例入门并掌握「Webpack4」(一) 后续:

  1. JS Tree Shaking
  2. CSS Tree Shaking
  3. 图片处置惩罚汇总
  4. 字体文件处置惩罚
  5. 处置惩罚第三方 js 库
  6. 开辟情势与 webpack-dev-server
  7. 开辟情势和临盆情势・实战
  8. 打包自定义函数库

九、JS Tree Shaking

demo9 源码地点

什么是 Tree Shaking?

字面意义是摇树,项目中没有运用的代码会在打包的时刻丢掉。JS 的 Tree Shaking 依靠的是 ES6 的模块体系(比方:import 和 export)

项目目次以下:

《24 个实例入门并控制「Webpack4」(二)》

在 util.js 文件中写入测试代码

// util.js
export function a() {
  return 'this is function "a"'
}

export function b() {
  return 'this is function "b"'
}

export function c() {
  return 'this is function "c"'
}

在 app.js 中援用 util.js 的 function a() 函数,按需引入

// app.js
import { a } from './vendor/util'
console.log(a())

敕令行运转 webpack 打包后,翻开打包后天生的 /dist/app.bundle.js 文件。查找我们 a() 函数输出的字符串,以下图所示:

《24 个实例入门并控制「Webpack4」(二)》

假如将查找内容换成 this is function "c" 或许 this is function "b", 并没有相干查找结果。申明 JS Tree Shaking 胜利。

1. 怎样处置惩罚第三方 JS 库?

关于常常运用的第三方库(比方 jQuery、lodash 等等),怎样完成 Tree Shaking ?

下面以 lodash.js 为例,举行引见。

装置 lodash.js : npm install lodash --save

在 app.js 中援用 lodash.js 的一个函数:

// app.js
import { chunk } from 'lodash'
console.log(chunk([1, 2, 3], 2))

敕令行打包。以下图所示,打包后大小是 70kb。明显,只援用了一个函数,不应该这么大。并没有举行 Tree Shaking。

《24 个实例入门并控制「Webpack4」(二)》

开首讲过,js tree shaking 运用的是 ES 的模块体系。而 lodash.js 运用的是 CommonJS 而不是ES6 的写法。所以,装置对应的模块体系即可。

装置 lodash.js 的 ES 写法的版本:npm install lodash-es --save

修正一下 app.js:

// app.js
import { chunk } from 'lodash-es'
console.log(chunk([1, 2, 3], 2))

再次打包,打包结果只要 3.5KB(以下图所示)。明显,tree shaking 胜利。

《24 个实例入门并控制「Webpack4」(二)》

在一些对加载速率敏感的项目中运用第三方库,请注重库的写法是不是相符 ES 模板体系范例,以轻易 webpack 举行 tree shaking。

十、CSS Tree Shaking

demo10 源码地点

CSS Tree Shaking 并不像 JS Tree Shaking 那样轻易邃晓,起首要模拟一个着实的项目环境,来表现 CSS 的 Tree Shaking 的设置和结果。

此章节源码基于第八节处置惩罚 CSS 项目上做修正

我们起首编写 /src/css/base.css 款式文件,在文件中,我们编写了 3 个款式类。但在代码中,我们只会运用 .box 和 .box–big 这两个类。代码以下所示:

/* base.css */
html {
  background: red;
}

.box {
  height: 200px;
  width: 200px;
  border-radius: 3px;
  background: green;
}

.box--big {
  height: 300px;
  width: 300px;
  border-radius: 5px;
  background: red;
}

.box-small {
  height: 100px;
  width: 100px;
  border-radius: 2px;
  background: yellow;
}

依据平常运用习气,DOM 操纵来完成款式的增加和卸载,是一向技术手段。所以,进口文件 /src/app.js 中建立了一个 <div> 标签,而且将它的类设为 .box

// app.js
import base from './css/base.css'

// 给 app 标签再加一个 div 而且类名为 box
var app = document.getElementById('app')
var div = document.createElement('div')
div.className = 'box'
app.appendChild(div)

末了,为了让环境更靠近现实环境,我们在 index.html 的一个标签,也援用了定义好的 box-big 款式类。

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>CSS Tree Shaking</title>
  </head>

  <body>
    <div id="app">
      <div class="box-big"></div>
    </div>
  </body>
</html>

PurifyCSS将协助我们举行 CSS Tree Shaking 操纵。为了能正确指明要举行 Tree Shaking 的 CSS 文件,另有 glob-all (另一个第三方库)。

glob-all 的作用就是协助 PurifyCSS 举行途径处置惩罚,定位要做 Tree Shaking 的途径文件。

装置依靠:

npm i glob-all purify-css purifycss-webpack --save-dev

更改设置文件:

const path = require('path')

const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 将 css 零丁打包成文件

const PurifyCSS = require('purifycss-webpack')
const glob = require('glob-all')

module.exports = {
  entry: {
    app: './src/app.js'
  },
  output: {
    publicPath: './', // js 援用的途径或许 CDN 地点
    path: path.resolve(__dirname, 'dist'), // 打包文件的输出目次
    filename: '[name].bundle.js', // 代码打包后的文件名
    chunkFilename: '[name].js' // 代码拆分后的文件名
  },
  module: {
    rules: [
      {
        test: /\.css$/, // 针对 .scss 或许 .css 后缀的文件设置 loader
        use: [
          {
            loader: MiniCssExtractPlugin.loader
          },
          'css-loader'
        ]
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      // 打包输出HTML
      title: '自动天生 HTML',
      minify: {
        // 紧缩 HTML 文件
        removeComments: true, // 移除 HTML 中的解释
        collapseWhitespace: true, // 删除空白符与换行符
        minifyCSS: true // 紧缩内联 css
      },
      filename: 'index.html', // 天生后的文件名
      template: 'index.html', // 依据此模版天生 HTML 文件
      chunks: ['app'] // entry中的 app 进口才会被打包
    }),
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: '[id].css'
    }),
    // 消灭无用 css
    new PurifyCSS({
      paths: glob.sync([
        // 要做 CSS Tree Shaking 的途径文件
        path.resolve(__dirname, './*.html'), // 请注重,我们一样需要对 html 文件举行 tree shaking
        path.resolve(__dirname, './src/*.js')
      ])
    })
  ]
}

打包完检察 dist/app.css 文件

《24 个实例入门并控制「Webpack4」(二)》

在 index.html 和 src/app.js 中援用的款式都被打包了,而没有被运用的款式类–box-small,没有被打包进去

十一、图片处置惩罚汇总

demo11 源码地点

目次构造:

《24 个实例入门并控制「Webpack4」(二)》

webpack4 中的图片经常使用的基本操纵:

  • 图片处置惩罚和 Base64 编码
  • 图片紧缩
  • 合成雪碧图

(一) 准备工作

如项目代码目次展现的那样,除了罕见的 app.js 作为进口文件,我们将用到的 3 张图片放在 /src/assets/imgs/ 目次下,并在款式文件 base.css 中援用这些图片。

剩下的内容交给 webpack 打包处置惩罚即可。款式文件和进口 app.js 文件的代码离别以下所示:

/* base.css */
*,
body {
  margin: 0;
  padding: 0;
}
.box {
  height: 400px;
  width: 400px;
  border: 5px solid #000;
  color: #000;
}
.box div {
  width: 100px;
  height: 100px;
  float: left;
}
.box .ani1 {
  background: url('./../assets/imgs/1.jpg') no-repeat;
}
.box .ani2 {
  background: url('./../assets/imgs/2.png') no-repeat;
}
.box .ani3 {
  background: url('./../assets/imgs/3.png') no-repeat;
}

app.js

import './css/base.css'

装置依靠:

npm install url-loader file-loader --save-dev

(二) 图片处置惩罚和 base64 编码

webpack.config.js 中的 module.rules 选项中举行设置,以完成让 loader 辨认图片后缀名,而且举行指定的处置惩罚操纵。

module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpg|jpeg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              name: '[name]-[hash:5].min.[ext]',
              outputPath: 'images/', //输出到 images 文件夹
              limit: 20000 //把小于 20kb 的文件转成 Base64 的花样
            }
          }
        ]
      }
    ]
  }
}

完整的设置文件

const path = require('path')

const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 将 css 零丁打包成文件

module.exports = {
  entry: {
    app: './src/app.js'
  },
  output: {
    publicPath: './', // js 援用的途径或许 CDN 地点
    path: path.resolve(__dirname, 'dist'), // 打包文件的输出目次
    filename: '[name].bundle.js', // 代码打包后的文件名
    chunkFilename: '[name].js' // 代码拆分后的文件名
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader
          },
          'css-loader'
        ]
      },
      {
        test: /\.(png|jpg|jpeg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              name: '[name]-[hash:5].min.[ext]',
              outputPath: 'images/', //输出到 images 文件夹
              limit: 20000 //把小于 20kb 的文件转成 Base64 的花样
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      // 打包输出HTML
      title: '自动天生 HTML',
      minify: {
        // 紧缩 HTML 文件
        removeComments: true, // 移除 HTML 中的解释
        collapseWhitespace: true, // 删除空白符与换行符
        minifyCSS: true // 紧缩内联 css
      },
      filename: 'index.html', // 天生后的文件名
      template: 'index.html', // 依据此模版天生 HTML 文件
      chunks: ['app'] // entry中的 app 进口才会被打包
    }),
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: '[id].css'
    })
  ]
}

打包项目,检察打包结果,并在浏览器中翻开 index.html 文件

《24 个实例入门并控制「Webpack4」(二)》

《24 个实例入门并控制「Webpack4」(二)》

能够看到除了 1.jpg,别的两张图片已被打包成 base64 花样,在 app.css 文件中

1.jpg 这个文件凌驾我们在 url-loader 选项中设置的 limit 值,所以被零丁打包

这就是运用了 file-loader 的才能,假如在 url-loader 中设置了 limit 的值,却没有装置 file-loader 依靠,会怎样?来尝尝看,起首卸载 file-loader 依靠npm uninstall file-loader,再运转打包敕令,npm run build

《24 个实例入门并控制「Webpack4」(二)》

假如图片较多,会发许多 http 要求,会下降页面机能。

url-loader 会将引入的图片编码,转为 base64 字符串。再把这串字符打包到文件中,终究只需要引入这个文件就可以接见图片了,节省了图片要求。

然则,假如图片较大,编码会斲丧机能。因而 url-loader 供应了一个 limit 参数,小于 limit 字节的文件会被转为 base64,大于 limit 的运用 file-loader 举行处置惩罚,零丁打包。

url-loader 依靠 file-loader,url-loader 能够看做是增强版的 file-loader

(三) 图片紧缩

图片紧缩需要运用 img-loader 插件,除此之外,针对差别的图片范例,还要援用差别的插件。比方,我们项目中运用的是 png 图片,因而,需要引入 imagemin-pngquant,而且指定紧缩率。紧缩 jpg/jpeg 图片为 imagemin-mozjpeg 插件

这里有个
bug,能够先不急着操纵,先把这一小节看完,再决议!!

装置依靠

npm i img-loader imagemin imagemin-pngquant imagemin-mozjpeg --save-dev

在之前的设置上更改:

{
  test: /\.(png|jpg|jpeg|gif)$/,
  use: [
    {
      loader: 'url-loader',
      options: {
        name: '[name]-[hash:5].min.[ext]',
        outputPath: 'images/', // 输出到 images 文件夹
        limit: 20000 //把小于 20kb 的文件转成 Base64 的花样
      }
    }
  ]
}

更改为:

{
  test: /\.(png|jpg|jpeg|gif)$/,
  use: [
    {
      loader: 'url-loader',
      options: {
        name: '[name]-[hash:5].min.[ext]',
        limit: 1000, // size <= 1KB
        outputPath: 'images/'
      }
    },
    // img-loader for zip img
    {
      loader: 'img-loader',
      options: {
        plugins: [
          require('imagemin-pngquant')({
            quality: '80' // the quality of zip
          }),
          require('imagemin-mozjpeg')({
            quality: '80'
          })
        ]
      }
    }
  ]
}

打包结果:

《24 个实例入门并控制「Webpack4」(二)》

《24 个实例入门并控制「Webpack4」(二)》

缘由在 png 图片上,jpg 图片能够紧缩,然则去 imagemin-pngquant github 上也没发明有人提出相似 issue ,百度、google 找了半天,照样没发明怎样处理 😭,因而运用另一种紧缩图片的插件 image-webpack-loader

起首卸载了之前的依靠:

npm uni img-loader imagemin imagemin-pngquant imagemin-mozjpeg

装置依靠:

npm i image-webpack-loader --save-dev

这个依靠装置的时候会比较久。。。能够先去做别的。。。

在之前的设置上更改:

{
  test: /\.(png|jpg|jpeg|gif)$/,
  use: [
    {
      loader: 'url-loader',
      options: {
        name: '[name]-[hash:5].min.[ext]',
        outputPath: 'images/', // 输出到 images 文件夹
        limit: 20000 //把小于 20kb 的文件转成 Base64 的花样
      }
    }
  ]
}

更改为:

{
  test: /\.(png|jpg|jpeg|gif)$/,
  use: [
    {
      loader: 'url-loader',
      options: {
        name: '[name]-[hash:5].min.[ext]',
        limit: 1000, // size <= 1KB
        outputPath: 'images/'
      }
    },
    // img-loader for zip img
    {
      loader: 'image-webpack-loader',
      options: {
        // 紧缩 jpg/jpeg 图片
        mozjpeg: {
          progressive: true,
          quality: 65 // 紧缩率
        },
        // 紧缩 png 图片
        pngquant: {
          quality: '65-90',
          speed: 4
        }
      }
    }
  ]
}

这里有意url-loaderlimit 属性值设的很小,不让它转化 png 图片为 base64,因为我们要测试紧缩 png 图片

打包结果:

《24 个实例入门并控制「Webpack4」(二)》

图片紧缩胜利,这里我细致看了下image-webpack-loader 的 github,着实这个 image-webpack-loader 插件内置了好几种图片紧缩的插件

《24 个实例入门并控制「Webpack4」(二)》

这里让我很迷惑,为何我直接装置 imagemin-pngquant 不可,反而运用 image-webpack-loader 却能够,因而我去检察 package-lock.json 文件,搜刮 image-webpack-loader

《24 个实例入门并控制「Webpack4」(二)》

我看了下我之前装置的是最新的版本, ^7.0.0 !!!

阿西吧… 终究找到题目所在,新版本有些题目没处置惩罚好,致使紧缩 png 图片失利,晓得题目就好办了,在 package.json 中,将 imagemin-pngquant 版本改成 ^6.0.0,从新 npm install

再依据之前的操纵,就可以够紧缩成了,对应版本以下:

{
  "devDependencies": {
    "imagemin": "^6.1.0",
    "imagemin-mozjpeg": "^8.0.0",
    "imagemin-pngquant": "^6.0.0",
    "img-loader": "^3.0.1"
  }
}

假如运用 image-webpack-loader ,版本为 4.6.0 ,引入的依靠版本也在白框内

《24 个实例入门并控制「Webpack4」(二)》

此次我照样运用 image-webpack-loader,朋友们能够自行挑选运用哪一个插件,只是 image-webpack-loader 引入了其他图片花样紧缩的依靠,如 svg/webp/gif 等,只装置 image-webpack-loader 就够了,而另一种则是要一个个插件装过去,着实原理都一样

经由此次调试,邃晓
并非最新的版本就是最好的,新版本或许有哪些地方没处置惩罚好,或许是不能兼容其他插件,致使报错

所以装置第三方依靠的时刻,照样要郑重一点npm install 默许是装置最新版,假如出了题目,回滚到之前的稳定版,不单单议适用于 webpack 插件,关于其他软件或许东西也是如许

写这一小节的时候为:2019-3-9,以后的版本更改涌现报错的话,能够不必装置最新版,回滚到之前的版本尝尝

(四) 天生雪碧图

装置依靠:

npm i postcss-loader postcss-sprites --save-dev

完整设置:

const path = require('path')

const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 将 css 零丁打包成文件

/*********** sprites config ***************/
let spritesConfig = {
  spritePath: './dist/images'
}
/******************************************/

module.exports = {
  entry: {
    app: './src/app.js'
  },
  output: {
    publicPath: './', // js 援用的途径或许 CDN 地点
    path: path.resolve(__dirname, 'dist'), // 打包文件的输出目次
    filename: '[name].bundle.js', // 代码打包后的文件名
    chunkFilename: '[name].js' // 代码拆分后的文件名
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader
          },
          'css-loader',
          /*********** loader for sprites ***************/
          {
            loader: 'postcss-loader',
            options: {
              ident: 'postcss',
              plugins: [require('postcss-sprites')(spritesConfig)]
            }
          }
          /*********************************************/
        ]
      },
      {
        test: /\.(png|jpg|jpeg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              name: '[name]-[hash:5].min.[ext]',
              limit: 1000, // size <= 1KB
              outputPath: 'images/'
            }
          },
          // img-loader for zip img
          {
            loader: 'image-webpack-loader',
            options: {
              // 紧缩 jpg/jpeg 图片
              mozjpeg: {
                progressive: true,
                quality: 65 // 紧缩率
              },
              // 紧缩 png 图片
              pngquant: {
                quality: '65-90',
                speed: 4
              }
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      // 打包输出HTML
      title: '自动天生 HTML',
      minify: {
        // 紧缩 HTML 文件
        removeComments: true, // 移除 HTML 中的解释
        collapseWhitespace: true, // 删除空白符与换行符
        minifyCSS: true // 紧缩内联 css
      },
      filename: 'index.html', // 天生后的文件名
      template: 'index.html', // 依据此模版天生 HTML 文件
      chunks: ['app'] // entry中的 app 进口才会被打包
    }),
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: '[id].css'
    })
  ]
}

打包后检察结果:

《24 个实例入门并控制「Webpack4」(二)》

《24 个实例入门并控制「Webpack4」(二)》

雪碧图是为了削减收集要求,所以被处置惩罚雪碧图的图片多为形形色色的 logo 或许大小相称的小图片

而关于大图片,不引荐运用雪碧图。如许会使得图片体积很大

除此之外,雪碧图要合营 css 代码举行定制化运用。要经由过程 css 代码在雪碧图上精准定位需要的图片

十二、字体文件处置惩罚

demo12 源码地点

项目目次为:

《24 个实例入门并控制「Webpack4」(二)》

package.json 中运用的依靠以下:

{
  "scripts": {
    "dev": "webpack --mode development",
    "build": "webpack --mode production"
  },
  "devDependencies": {
    "clean-webpack-plugin": "^2.0.0",
    "css-loader": "^2.1.0",
    "file-loader": "^3.0.1",
    "url-loader": "^1.1.2",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "mini-css-extract-plugin": "^0.5.0",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.2.3"
  }
}

app.js 中引入字体文件

import './assets/fonts/iconfont.css'

设置 webpack.config.js 文件来处置惩罚字体

借助 url-loader,能够辨认而且处置惩罚 eot、woff 等末端的字体文件。同时,依据字体文件大小,能够天真设置是不是举行 base64 编码。

下面的 demo 就是当文件大小小于 5000B 的时刻,举行 base64 编码。

const path = require('path')

const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 将 css 零丁打包成文件

module.exports = {
  entry: {
    app: './src/app.js'
  },
  output: {
    publicPath: './', // js 援用的途径或许 CDN 地点
    path: path.resolve(__dirname, 'dist'), // 打包文件的输出目次
    filename: '[name].bundle.js', // 代码打包后的文件名
    chunkFilename: '[name].js' // 代码拆分后的文件名
  },
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader
          },
          'css-loader'
        ]
      },
      {
        test: /\.(eot|woff2?|ttf|svg)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              name: '[name]-[hash:5].min.[ext]',
              limit: 5000, // fonts file size <= 5KB, use 'base64'; else, output svg file
              publicPath: 'fonts/',
              outputPath: 'fonts/'
            }
          }
        ]
      }
    ]
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      // 打包输出HTML
      title: '自动天生 HTML',
      minify: {
        // 紧缩 HTML 文件
        removeComments: true, // 移除 HTML 中的解释
        collapseWhitespace: true, // 删除空白符与换行符
        minifyCSS: true // 紧缩内联 css
      },
      filename: 'index.html', // 天生后的文件名
      template: 'index.html', // 依据此模版天生 HTML 文件
      chunks: ['app'] // entry中的 app 进口才会被打包
    }),
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: '[id].css'
    })
  ]
}

在 index.html 中运用字体

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>处置惩罚字体文件</title>
  </head>

  <body>
    <div id="app">
      <div class="box">
        <i class="iconfont icon-xiazai"></i>
        <i class="iconfont icon-shoucang"></i>
        <i class="iconfont icon-erweima"></i>
        <i class="iconfont icon-xiangshang"></i>
        <i class="iconfont icon-qiehuanzuhu"></i>
        <i class="iconfont icon-sort"></i>
        <i class="iconfont icon-yonghu"></i>
      </div>
    </div>
  </body>
</html>

打包后检察 index.html 文件,打包胜利

《24 个实例入门并控制「Webpack4」(二)》

十三、处置惩罚第三方 js 库

demo13 源码地点

项目目次:

《24 个实例入门并控制「Webpack4」(二)》

1. 怎样运用和治理第三方 JS 库?

项目做大以后,开辟者会更多专注在营业逻辑上,其他方面则全力运用第三方 JS 库来完成。

因为 js 变化着实太快,所以涌现了多种引入和治理第三方库的要领,经常使用的有 3 中:

  • CDN:<script></script> 标签引入即可
  • npm 包治理:如今最经常使用和最引荐的要领
  • 当地 js 文件:一些库因为汗青缘由,没有供应 ES6 版本,需要手动下载,放入项目目次中,再手动引入。

针对第三种要领,假如没有 webpack,则需要手动引入 import 或许 require 来加载文件;然则,webpack 供应了 alias 的设置,合营 webpack.ProvidePlugin 这款插件,能够跳过手动入,直接运用!

2. 编写进口文件

如项目目次图片所展现的,我们下载了 jquery.min.js,放到了项目中。同时,我们也经由过程 npm 装置了 jquery

《24 个实例入门并控制「Webpack4」(二)》

为了尽量模拟临盆环境,app.js 中运用了 &dollar; 来挪用 jq,还运用了 jQuery 来挪用 jq。

因为正式项目中,因为需要的依靠过量,挂载到 window 对象的库,很容易发生定名争执题目。此时,就需要重定名库。比方:&dollar; 就被换成了 jQuery。

在 app.js 中举行修正

// app.js
$('div').addClass('new')

jQuery('div').addClass('old')

// 运转webpack后
// 浏览器翻开 index.html, 检察 div 标签的 class
  1. 编写设置文件

webpack.ProvidePlugin 参数是键值对情势,键就是我们项目中运用的变量名,值就是键所指向的库。

webpack.ProvidePlugin 会先从 npm 装置的包中查找是不是有相符的库

假如 webpack 设置了 resolve.alias 选项(邃晓成 “别号”),那末 webpack.ProvidePlugin 就会顺着这条链一向找下去。

const path = require('path')
const webpack = require('webpack')

const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: {
    app: './src/app.js'
  },
  output: {
    publicPath: './', // js 援用的途径或许 CDN 地点
    path: path.resolve(__dirname, 'dist'), // 打包文件的输出目次
    filename: '[name].bundle.js', // 代码打包后的文件名
    chunkFilename: '[name].js' // 代码拆分后的文件名
  },
  resolve: {
    alias: {
      jQuery$: path.resolve(__dirname, 'src/vendor/jquery.min.js')
    }
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      // 打包输出HTML
      title: '自动天生 HTML',
      minify: {
        // 紧缩 HTML 文件
        removeComments: true, // 移除 HTML 中的解释
        collapseWhitespace: true, // 删除空白符与换行符
        minifyCSS: true // 紧缩内联 css
      },
      filename: 'index.html', // 天生后的文件名
      template: 'index.html', // 依据此模版天生 HTML 文件
      chunks: ['app'] // entry中的 app 进口才会被打包
    }),
    new webpack.ProvidePlugin({
      $: 'jquery', // npm
      jQuery: 'jQuery' // 当地Js文件
    })
  ]
}

修正 index.html 文件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>处置惩罚第三方 js 库</title>
  </head>
  <body>
    <div></div>
  </body>
</html>

打包并在 Chrome 中翻开 index.html。以下图所示,<div> 标签已被增加上了 oldnew 两个款式类。证实在 app.js 中运用的 &dollar; 和 jQuery 都胜利指向了 jquery 库。

《24 个实例入门并控制「Webpack4」(二)》

十四、开辟情势与 webpack-dev-server

demo14 源码地点

1. 为何需要开辟情势?

这十几节来我们运用最多的就是临盆环境,也就是实行 npm run build 敕令,打包项目中的种种文件及紧缩

而开辟情势就是指定 mode 为 development。对应我们在 package.json 中设置的,就是 npm run dev,在第二小节也触及到了这一点

在开辟情势下,我们需要对代码举行调试。对应的设置就是:devtool 设置为 source-map。在非开辟情势下,需要封闭此选项,以减小打包体积。概况见: devtool

在开辟情势下,还需要热重载路由重定向设置代办等功用,webpack4 已供应了 devServer 选项,启动一个当地服务器,让开辟者运用这些功用。

目次构造:

《24 个实例入门并控制「Webpack4」(二)》

装置依靠

npm i webpack-dev-server --save-dev

修正 package.json

{
  "scripts": {
    "dev": "webpack-dev-server --open",
    "build": "webpack --mode production"
  },
  "devDependencies": {
    "clean-webpack-plugin": "^2.0.0",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "jquery": "^3.3.1",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.2.3",
    "webpack-dev-server": "^3.2.1"
  }
}

因为我们在 package.json 中设置了 script,所以开启开辟情势直接 npm run dev 即可

《24 个实例入门并控制「Webpack4」(二)》

虽然掌握台输出了打包信息(假定我们已设置了热重载),然则磁盘上并没有建立 /dist/ 文件夹和打包文件。掌握台的打包文件的相干内容是存储在内存当中的。

修正 index.html 文件

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>webpack-dev-server</title>
  </head>

  <body>
    This is Index html
  </body>
</html>

依据项目目次,简朴封装下 /vendor/ 下的三个 js 文件,以轻易 app.js 挪用:

// minus.js
module.exports = function(a, b) {
  return a - b
}

// multi.js
define(function(require, factory) {
  'use strict'
  return function(a, b) {
    return a * b
  }
})

// sum.js
export default function(a, b) {
  console.log('I am sum.js')
  return a + b
}

app.js 中运用三种引入体式格局引入 js 文件:

import sum from './vendor/sum'
console.log('sum(1, 2) = ', sum(1, 2))

var minus = require('./vendor/minus')
console.log('minus(1, 2) = ', minus(1, 2))

require(['./vendor/multi'], function(multi) {
  console.log('multi(1, 2) = ', multi(1, 2))
})

如今最先更改 webpack.config.js, 完整的设置文件以下:

const webpack = require('webpack')
const path = require('path')

const CleanWebpackPlugin = require('clean-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')

module.exports = {
  entry: {
    app: './src/app.js'
  },
  output: {
    publicPath: '/', // js 援用的途径或许 CDN 地点
    path: path.resolve(__dirname, 'dist'), // 打包文件的输出目次
    filename: '[name].bundle.js', // 代码打包后的文件名
    chunkFilename: '[name].js' // 代码拆分后的文件名
  },
  mode: 'development', // 开辟情势
  devtool: 'source-map', // 开启调试
  devServer: {
    contentBase: path.join(__dirname, 'dist'),
    port: 8000, // 当地服务器端口号
    hot: true, // 热重载
    overlay: true, // 假如代码失足,会在浏览器页面弹出“浮动层”。相似于 vue-cli 等脚手架
    proxy: {
      // 跨域代办转发
      '/comments': {
        target: 'https://m.weibo.cn',
        changeOrigin: true,
        logLevel: 'debug',
        headers: {
          Cookie: ''
        }
      }
    },
    historyApiFallback: {
      // HTML5 history情势
      rewrites: [{ from: /.*/, to: '/index.html' }]
    }
  },
  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      // 打包输出HTML
      title: '自动天生 HTML',
      minify: {
        // 紧缩 HTML 文件
        removeComments: true, // 移除 HTML 中的解释
        collapseWhitespace: true, // 删除空白符与换行符
        minifyCSS: true // 紧缩内联 css
      },
      filename: 'index.html', // 天生后的文件名
      template: 'index.html', // 依据此模版天生 HTML 文件
      chunks: ['app'] // entry中的 app 进口才会被打包
    }),
    new webpack.HotModuleReplacementPlugin(), // 热布置模块
    new webpack.NamedModulesPlugin(),
    new webpack.ProvidePlugin({
      $: 'jquery', // npm
      jQuery: 'jQuery' // 当地Js文件
    })
  ]
}

对上面的设置举行零丁剖析:

  • 模块热更新

模块热更新需要 HotModuleReplacementPluginNamedModulesPlugin 这两个插件,而且递次不能错,而且指定 devServer.hot 为 true

const webpack = require('webpack') // 引入 webpack

module.exports = {
  plugins: [
    new webpack.HotModuleReplacementPlugin(), // 热布置模块
    new webpack.NamedModulesPlugin()
  ]
}

有了这两个插件,在项目的 js 代码中能够针对侦测到变动的文件而且做出相干处置惩罚,也就不必写完代码从新革新页面,它会自动检测变动的代码而且在页面上更改

注重是
js 代码,假如你去修改 index.html 文件,保留后,页面并不会更改,反之你去修正了 js 文件,保留后,页面会更新

比方,我们启动开辟情势后,修正了 vendor/sum.js 这个文件,此时,需要在浏览器的掌握台打印一些信息。那末,app.js 中就可以够这么写:

if (module.hot) {
  // 检测是不是有模块热更新
  module.hot.accept('./vendor/sum.js', function() {
    // 针对被更新的模块, 举行进一步操纵
    console.log('/vendor/sum.js is changed')
  })
}

每当 sum.js 被修正后,都能够自动实行回调函数。

浏览器掌握台输出信息以下:

《24 个实例入门并控制「Webpack4」(二)》

然则我们一样平常开辟中运用 vue 脚手架基础没有写过如许的代码,也能热更新,是因为 vue-loader 中内置了这类要领,css-loader 中也有,所以我们改完 js 和 css 代码就可以直接看到更新

  • 跨域代办

跟着前后端星散开辟的提高,跨域要求变得愈来愈罕见。为了疾速开辟,能够运用 devServer.proxy 做一个代办转发,来绕过浏览器的跨域限定。

devServer 模块的底层是运用了 http-proxy-middleware,能设置的东西异常多

依据前面的设置文件,假如想挪用微博的一个接口:https://m.weibo.cn/comments/h…。只需要在代码中对 /comments/hotflow 举行要求即可,在 app.js 中增加以下代码:

$.get(
  '/comments/hotflow',
  {
    id: '4263554020904293',
    mid: '4263554020904293',
    max_id_type: '0'
  },
  function(data) {
    console.log(data)
  }
)

上面代码是运用 jQuery 发送 get 要求,假如是在 vue 项目中,平常是运用 axios 来发送要求

修正完 app.js 后保留,翻开之前的 localhost:8000 网页,能够看到 Network 发送的要求

《24 个实例入门并控制「Webpack4」(二)》

  • HTML5–History

当项目运用 HTML5 History API 时,恣意的 404 相应都能够需要被替代为 index.html。

在 SPA(单页运用)中,任何相应直接被替代为 index.html。

在 vuejs 官方的脚手架 vue-cli 中,开辟情势下设置以下:

historyApiFallback: {
  // HTML5 history情势
  rewrites: [{ from: /.*/, to: '/index.html' }]
}

终究 app.js 中的代码以下:

import sum from './vendor/sum'
console.log('sum(1, 2) = ', sum(1, 2))

var minus = require('./vendor/minus')
console.log('minus(1, 2) = ', minus(1, 2))

require(['./vendor/multi'], function(multi) {
  console.log('multi(1, 2) = ', multi(1, 2))
})

$.get(
  '/comments/hotflow',
  {
    id: '4263554020904293',
    mid: '4263554020904293',
    max_id_type: '0'
  },
  function(data) {
    console.log(data)
  }
)

if (module.hot) {
  // 检测是不是有模块热更新
  module.hot.accept('./vendor/sum.js', function() {
    // 针对被更新的模块, 举行进一步操纵
    console.log('/vendor/sum.js is changed')
  })
}

翻开掌握台,能够看到代码都平常运转没有失足。除此之外,因为开启了 source-map,所以能够定位代码位置(下图红框内):

《24 个实例入门并控制「Webpack4」(二)》

参考文章: webpack4 系列教程 (十五):开辟情势与 webpack-dev-server

十五、开辟情势和临盆情势・实战

demo15 源码地点

起首,新建一个文件夹:demo15,实行 npm init -y 初始化 package.json,天生后的文件以下:

{
  "name": "example",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "keywords": [],
  "author": "",
  "license": "ISC"
}

我们先将无用的代码消灭掉,只留下症结代码:

{
  "scripts": {}
}

起首装置 webpack 所需依靠

npm i webpack webpack-cli webpack-dev-server --save-dev

装置 babel7,因为如今主如果用 ES6 来编写代码,所以需要转译

npm i @babel/core babel-loader @babel/preset-env @babel/plugin-transform-runtime --save-dev
npm i @babel/polyfill @babel/runtime

如今 package.json 中的依靠为:

{
  "scripts": {},
  "devDependencies": {
    "@babel/core": "^7.3.4",
    "@babel/plugin-transform-runtime": "^7.3.4",
    "@babel/preset-env": "^7.3.4",
    "babel-loader": "^8.0.5",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.2.3",
    "webpack-dev-server": "^3.2.1"
  },
  "dependencies": {
    "@babel/polyfill": "^7.2.5",
    "@babel/runtime": "^7.3.4"
  }
}

新建 .babelrc 来设置 babel 插件,代码以下:

{
  "presets": ["@babel/preset-env"],
  "plugins": ["@babel/plugin-transform-runtime"]
}

新建 .browserslistrc 文件设置该项目所支撑的浏览器版本

# 所支撑的浏览器版本

> 1% # 环球运用状况统计挑选的浏览器版本
last 2 version # 每一个浏览器的末了两个版本
not ie <= 8 # 消除小于 ie8 及以下的浏览器

在最先设置 webpack.config.js 文件之前,需要注重一下,因为如今我们是有两种情势,
production(临盆)  和
development(开辟)  情势。

装置自动天生 html 依靠

npm i html-webpack-plugin html-loader clean-webpack-plugin --save-dev

装置 css/字体图标处置惩罚依靠

npm i css-loader style-loader mini-css-extract-plugin optimize-css-assets-webpack-plugin --save-dev

装置 scss 处置惩罚依靠

npm i node-sass sass-loader --save-dev

为差别内核的浏览器加上 CSS 前缀

npm install postcss-loader autoprefixer --save-dev

图片及字体处置惩罚:

npm i url-loader file-loader image-webpack-loader --save-dev

第三方 js 库

npm i jquery

如今 package.json 为:

{
  "scripts": {},
  "devDependencies": {
    "@babel/core": "^7.3.4",
    "@babel/plugin-transform-runtime": "^7.3.4",
    "@babel/preset-env": "^7.3.4",
    "autoprefixer": "^9.4.10",
    "babel-loader": "^8.0.5",
    "clean-webpack-plugin": "^2.0.0",
    "css-loader": "^2.1.1",
    "file-loader": "^3.0.1",
    "html-loader": "^0.5.5",
    "html-webpack-plugin": "^3.2.0",
    "image-webpack-loader": "^4.6.0",
    "mini-css-extract-plugin": "^0.5.0",
    "node-sass": "^4.11.0",
    "optimize-css-assets-webpack-plugin": "^5.0.1",
    "postcss-loader": "^3.0.0",
    "sass-loader": "^7.1.0",
    "style-loader": "^0.23.1",
    "url-loader": "^1.1.2",
    "webpack": "^4.29.6",
    "webpack-cli": "^3.2.3",
    "webpack-dev-server": "^3.2.1"
  },
  "dependencies": {
    "@babel/polyfill": "^7.2.5",
    "@babel/runtime": "^7.3.4",
    "jquery": "^3.3.1"
  }
}

之前我们大多都是写临盆情势,也就是常常说的打包,然则我们一样平常开辟项目,用的是开辟情势。

只要在项目做完后,要布置到 nginx 上的时刻才运用临盆情势,将代码打包后放到 nginx

之所以要分两种情势是因为,开辟情势下,需要加速编译的速率,能够热更新以及设置跨域地点,开启源码调试(devtool: ‘source-map’)

而天生情势下,则需要紧缩 js/css 代码,拆分大众代码段,拆分第三方 js 库等操纵

所以这里的设置我们分红三个文件来写,一个是临盆设置,一个是开辟设置,末了一个是基本设置

即:webpack.base.conf.js(基本设置)、webpack.dev.conf.js(开辟设置)、webpack.prod.conf.js(临盆设置)

新建 build 文件夹,建立上述三个文件,项目构造为:

《24 个实例入门并控制「Webpack4」(二)》

这里需要运用到一个插件,webpack-merge 用来兼并设置,比方开辟环境就兼并开辟设置 + 基本设置,临盆就兼并临盆设置 + 基本设置

npm i webpack-merge --save-dev

先简朴写个 webpack.base.conf.js 的示例代码

const merge = require('webpack-merge')

const productionConfig = require('./webpack.prod.conf') // 引入临盆环境设置文件
const developmentConfig = require('./webpack.dev.conf') // 引入开辟环境设置文件

const baseConfig = {} // ... 省略

module.exports = env => {
  let config = env === 'production' ? productionConfig : developmentConfig
  return merge(baseConfig, config) // 兼并 大众设置 和 环境设置
}
  • 引入 webpack-merge 插件来兼并设置
  • 引入临盆环境和开辟环境
  • 编写基本设置
  • 导出兼并后的设置文件

在代码中辨别差别环境:

module.exports = env => {
  let config = env === 'production' ? productionConfig : developmentConfig
  return merge(baseConfig, config) // 兼并 大众设置 和 环境设置
}

这里的 env 在 package.json 中举行设置,修正 scripts,增加 “dev” 和 “build” 敕令

注重,这里有个 –env 字段,与 webpack.base.conf.js 中的 env 是联动的,通知它当前是什么环境,然后兼并成什么环境

{
  "scripts": {
    "dev": "webpack-dev-server --env development --open --config build/webpack.base.conf.js",
    "build": "webpack --env production --config build/webpack.base.conf.js"
  }
}

(一) 编写基本设置

const webpack = require('webpack')
const merge = require('webpack-merge')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 将 css 零丁打包成文件
const CleanWebpackPlugin = require('clean-webpack-plugin')

const path = require('path')

const productionConfig = require('./webpack.prod.conf.js') // 引入临盆环境设置文件
const developmentConfig = require('./webpack.dev.conf.js') // 引入开辟环境设置文件

/**
 * 依据差别的环境,天生差别的设置
 * @param {String} env "development" or "production"
 */
const generateConfig = env => {
  // 将需要的 Loader 和 Plugin 零丁声明

  let scriptLoader = [
    {
      loader: 'babel-loader'
    }
  ]

  let cssLoader = [
    'style-loader',
    'css-loader',
    'sass-loader', // 运用 sass-loader 将 scss 转为 css
    'postcss-loader' // 运用 postcss 为 css 加上浏览器前缀
  ]

  let cssExtractLoader = [
    {
      loader: MiniCssExtractPlugin.loader
    },
    'css-loader',
    'sass-loader', // 运用 sass-loader 将 scss 转为 css
    'postcss-loader' // 运用 postcss 为 css 加上浏览器前缀
  ]

  let fontLoader = [
    {
      loader: 'url-loader',
      options: {
        name: '[name]-[hash:5].min.[ext]',
        limit: 5000, // fonts file size <= 5KB, use 'base64'; else, output svg file
        publicPath: 'fonts/',
        outputPath: 'fonts/'
      }
    }
  ]

  let imageLoader = [
    {
      loader: 'url-loader',
      options: {
        name: '[name]-[hash:5].min.[ext]',
        limit: 10000, // size <= 10KB
        outputPath: 'images/'
      }
    },
    // 图片紧缩
    {
      loader: 'image-webpack-loader',
      options: {
        // 紧缩 jpg/jpeg 图片
        mozjpeg: {
          progressive: true,
          quality: 50 // 紧缩率
        },
        // 紧缩 png 图片
        pngquant: {
          quality: '65-90',
          speed: 4
        }
      }
    }
  ]

  let styleLoader =
    env === 'production'
      ? cssExtractLoader // 临盆环境下紧缩 css 代码
      : cssLoader // 开辟环境:页内款式嵌入

  return {
    entry: { app: './src/app.js' },
    output: {
      publicPath: env === 'development' ? '/' : './',
      path: path.resolve(__dirname, '..', 'dist'),
      filename: '[name]-[hash:5].bundle.js',
      chunkFilename: '[name]-[hash:5].chunk.js'
    },
    module: {
      rules: [
        { test: /\.js$/, exclude: /(node_modules)/, use: scriptLoader },
        { test: /\.(sa|sc|c)ss$/, use: styleLoader },
        { test: /\.(eot|woff2?|ttf|svg)$/, use: fontLoader },
        { test: /\.(png|jpg|jpeg|gif)$/, use: imageLoader }
      ]
    },
    plugins: [
      // 开辟环境和临盆环境两者均需要的插件
      new HtmlWebpackPlugin({
        title: 'webpack4 实战',
        filename: 'index.html',
        template: path.resolve(__dirname, '..', 'index.html'),
        // chunks: ['app'],
        minify: {
          collapseWhitespace: true
        }
      }),
      new webpack.ProvidePlugin({ $: 'jquery' }),
      new CleanWebpackPlugin()
    ]
  }
}

module.exports = env => {
  let config = env === 'production' ? productionConfig : developmentConfig
  return merge(generateConfig(env), config) // 兼并 大众设置 和 环境设置
}

以上设置发起多看几遍熟习熟习,为何要如许写

(二) 编写开辟环境设置文件

const webpack = require('webpack')

const path = require('path')

module.exports = {
  mode: 'development',
  devtool: 'source-map', // 调试源码
  devServer: {
    contentBase: path.join(__dirname, '../dist/'),
    port: 8000,
    hot: true,
    overlay: true,
    proxy: {
      '/comments': {
        target: 'https://m.weibo.cn',
        changeOrigin: true,
        logLevel: 'debug',
        headers: {
          Cookie: ''
        }
      }
    },
    historyApiFallback: true
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin()
  ]
}

开辟设置主如果设置跨域、开启源码调试、热更新

(三) 编写临盆环境设置文件

const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 将 css 零丁打包成文件
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin') // 紧缩 css

module.exports = {
  mode: 'production',
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        jquery: {
          name: 'chunk-jquery', // 零丁将 jquery 拆包
          priority: 15,
          test: /[\\/]node_modules[\\/]jquery[\\/]/
        }
      }
    }
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: '[id].css'
    }),
    // 紧缩 css
    new OptimizeCssAssetsPlugin({
      assetNameRegExp: /\.css$/g, //一个正则表达式,指导应优化/最小化的资产的称号。供应的正则表达式针对设置中ExtractTextPlugin实例导出的文件的文件名运转,而不是源CSS文件的文件名。默许为/\.css$/g
      cssProcessor: require('cssnano'), //用于优化\最小化 CSS 的 CSS处置惩罚器,默许为 cssnano
      cssProcessorOptions: { safe: true, discardComments: { removeAll: true } }, //传递给 cssProcessor 的选项,默许为{}
      canPrint: true //一个布尔值,指导插件是不是能够将音讯打印到掌握台,默许为 true
    })
  ]
}
**临盆设置主如果拆分代码,紧缩 css**

(四) 测试开辟情势

运转 npm run dev

《24 个实例入门并控制「Webpack4」(二)》

而且自动翻开浏览器,图片和字体都出来了,翻开掌握台也能看到跨域胜利、源码定位,因为将 devtool 设置为 ‘source-map’,所以就会天生 map 文件,体积较大

《24 个实例入门并控制「Webpack4」(二)》

(五) 测试临盆情势

运转 npm run build

《24 个实例入门并控制「Webpack4」(二)》

翻开 dist/index.html 文件

《24 个实例入门并控制「Webpack4」(二)》

临盆情势下跨域失利是很平常的,而且假如是 vue 项目打包完以后是没法直接翻开 index.html 文件检察结果的,必需要放在服务器上,平常都是将打包后的文件放入 nginx 中,在 nginx 中设置跨域地点

另有一种设置 webpack 开辟和临盆环境的体式格局,会比较经常使用:

修正 webpack.base.conf.js

const path = require('path')
const webpack = require('webpack')
const HtmlWebpackPlugin = require('html-webpack-plugin')
const CleanWebpackPlugin = require('clean-webpack-plugin')

module.exports = {
  entry: {
    app: './src/app.js'
  },
  output: {
    path: path.resolve(__dirname, '..', 'dist')
  },
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader'
          }
        ]
      },
      {
        test: /\.(png|jpg|jpeg|gif)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              name: '[name]-[hash:5].min.[ext]',
              limit: 1000, // size <= 1KB
              outputPath: 'images/'
            }
          },
          // img-loader for zip img
          {
            loader: 'image-webpack-loader',
            options: {
              // 紧缩 jpg/jpeg 图片
              mozjpeg: {
                progressive: true,
                quality: 65 // 紧缩率
              },
              // 紧缩 png 图片
              pngquant: {
                quality: '65-90',
                speed: 4
              }
            }
          }
        ]
      },
      {
        test: /\.(eot|ttf|svg)$/,
        use: {
          loader: 'url-loader',
          options: {
            name: '[name]-[hash:5].min.[ext]',
            limit: 5000, // fonts file size <= 5KB, use 'base64'; else, output svg file
            publicPath: 'fonts/',
            outputPath: 'fonts/'
          }
        }
      }
    ]
  },
  plugins: [
    // 开辟环境和临盆环境两者均需要的插件
    new HtmlWebpackPlugin({
      title: 'webpack4 实战',
      filename: 'index.html',
      template: path.resolve(__dirname, '..', 'index.html'),
      minify: {
        collapseWhitespace: true
      }
    }),
    new webpack.ProvidePlugin({ $: 'jquery' }),
    new CleanWebpackPlugin()
  ],
  performance: false
}

修正 webpack.dev.conf.js

const webpack = require('webpack')
const merge = require('webpack-merge')
const commonConfig = require('./webpack.base.conf.js')

const path = require('path')

const devConfig = {
  mode: 'development',
  output: {
    filename: '[name].js',
    chunkFilename: '[name].js'
  },
  module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          'style-loader',
          {
            loader: 'css-loader',
            options: {
              importLoaders: 2 // 在一个 css 中引入了另一个 css,也会实行之前两个 loader,即 postcss-loader 和 sass-loader
            }
          },
          'sass-loader', // 运用 sass-loader 将 scss 转为 css
          'postcss-loader' // 运用 postcss 为 css 加上浏览器前缀
        ]
      }
    ]
  },
  devtool: 'cheap-module-eval-soure-map',
  devServer: {
    contentBase: path.join(__dirname, '../dist/'),
    port: 8000,
    hot: true,
    overlay: true,
    proxy: {
      '/comments': {
        target: 'https://m.weibo.cn',
        changeOrigin: true,
        logLevel: 'debug',
        headers: {
          Cookie: ''
        }
      }
    },
    historyApiFallback: true
  },
  plugins: [
    new webpack.HotModuleReplacementPlugin(),
    new webpack.NamedModulesPlugin()
  ]
}

module.exports = merge(commonConfig, devConfig)

修正 webpack.prod.conf.js

const merge = require('webpack-merge')
const commonConfig = require('./webpack.base.conf.js')

const MiniCssExtractPlugin = require('mini-css-extract-plugin') // 将 css 零丁打包成文件
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin') // 紧缩 css

const prodConfig = {
  mode: 'production',
  output: {
    filename: '[name].[contenthash].js',
    chunkFilename: '[name].[contenthash].js'
  },
  devtool: 'cheap-module-source-map',
  module: {
    rules: [
      {
        test: /\.(sa|sc|c)ss$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader
          },
          {
            loader: 'css-loader',
            options: {
              importLoaders: 2 // 在一个 css 中引入了另一个 css,也会实行之前两个 loader,即 postcss-loader 和 sass-loader
            }
          },
          'sass-loader', // 运用 sass-loader 将 scss 转为 css
          'postcss-loader' // 运用 postcss 为 css 加上浏览器前缀
        ]
      }
    ]
  },
  optimization: {
    splitChunks: {
      chunks: 'all',
      cacheGroups: {
        jquery: {
          name: 'jquery', // 零丁将 jquery 拆包
          priority: 15,
          test: /[\\/]node_modules[\\/]jquery[\\/]/
        },
        vendors: {
          test: /[\\/]node_modules[\\/]/,
          name: 'vendors'
        }
      }
    }
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name]-[contenthash].css',
      chunkFilename: '[id]-[contenthash].css'
    }),
    // 紧缩 css
    new OptimizeCssAssetsPlugin({
      assetNameRegExp: /\.css$/g, //一个正则表达式,指导应优化/最小化的资产的称号。供应的正则表达式针对设置中ExtractTextPlugin实例导出的文件的文件名运转,而不是源CSS文件的文件名。默许为/\.css$/g
      cssProcessor: require('cssnano'), //用于优化\最小化 CSS 的 CSS处置惩罚器,默许为 cssnano
      cssProcessorOptions: { safe: true, discardComments: { removeAll: true } }, //传递给 cssProcessor 的选项,默许为{}
      canPrint: true //一个布尔值,指导插件是不是能够将音讯打印到掌握台,默许为 true
    })
  ]
}

module.exports = merge(commonConfig, prodConfig)

修正 package.json 的 script 敕令

{
  "scripts": {
    "dev": "webpack-dev-server --open --config ./build/webpack.dev.conf.js",
    "build": "webpack --config ./build/webpack.prod.conf.js"
  }
}

在之前的基本又修正了一下设置,从新打包即可

十六、打包自定义函数库

demo16 源码地点

新建 index.jsmath.jsstring.js

// index.js
import * as math from './math'
import * as string from './string'

export default { math, string }

// math.js
export function add(a, b) {
  return a + b
}

export function minus(a, b) {
  return a - b
}

export function multiply(a, b) {
  return a * b
}

export function division(a, b) {
  return a / b
}

// string.js
export function join(a, b) {
  return a + ' ' + b
}

代码写完,运用 webpack 打包,装置 webpack,-D 示意 –save-dev 的简写

npm i webpack webpack-cli -D

修正 package.json

{
  "name": "library",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "build": "webpack"
  },
  "keywords": [],
  "author": "xh",
  "license": "MIT",
  "devDependencies": {
    "webpack": "^4.29.6",
    "webpack-cli": "^3.3.0"
  }
}

"license": "MIT"示意完整开源的协定,name 示意你的组件库的称号

新建 webpack.config.js 并设置

const path = require('path')

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'library.js'
  }
}

运转打包敕令,天生 library.js 文件

《24 个实例入门并控制「Webpack4」(二)》

这个文件就可以够在项目中用了,然则我们如今是要做一个开源库,是给他人用的,他人能够会这么用

// ES module
import library from 'library'

// CommonJS
const library = require('library')

// AMD
require(['library'], function() {})

假如我们要支撑这三种情势的运用,能够在 webpack 里设置,加上 libraryTarget 参数

const path = require('path')

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'library.js',
    libraryTarget: 'umd'
  }
}

固然,假如你愿望用户还能够运用 script 标签的情势引入

<script src="library.js"></script>

用户愿望能够经由过程 library 全局变量来运用,比方 library.math 要怎样办

能够再设置一个参数,叫 library

const path = require('path')

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'library.js',
    library: 'root', // root 能够随意替换,不是固定值
    libraryTarget: 'umd'
  }
}

umd 是支撑前面三种语法,然则不支撑全局变量这类用法,假如设置了 library,打包以后就会将代码挂载到 root 这个全局变量上,经由过程 script 来引入 library,如今来打包一下,打包完以厥后测试用 script 标签来引入我们写的库

在 dist 目次下新建个 index.html 文件,并翻开页面

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <meta http-equiv="X-UA-Compatible" content="ie=edge" />
    <title>自定义库</title>
    <script src="./library.js"></script>
  </head>
  <body></body>
</html>

在掌握台中输入 root,回车,就可以看到我们前面封装的函数了

《24 个实例入门并控制「Webpack4」(二)》

libraryTarget: 'umd' 假如将 umd 改成 this

再去打包,在掌握台输入 this.root 也能看到结果

《24 个实例入门并控制「Webpack4」(二)》

libraryTarget 也能够填 window,假如在 node 环境下也能够运用 global

不过平常我们都是运用 umd

另有一种状况要注重,我们如今写的 string.js 我以为写的不好,lodash 写的更好,我要引入这个第三方库,来替代我写的一些功用

npm install lodash

// string.js
import _ from 'lodash'

export function join(a, b) {
  return _.join([a, b], ' ')
}

从新打包,体积为 70kb,因为我们也把 lodash 也打包进去了

《24 个实例入门并控制「Webpack4」(二)》

他人要运用我们的库的话,需要如许 import library from 'library',或许他人也会用到 lodash 库,结果变成了如许:

import _ from 'lodash'
import library from 'library'

终究用户的代码中就会存在两份 lodash 的代码,这类状况就要再去更改一下我们的 webpack 设置

const path = require('path')

module.exports = {
  mode: 'production',
  entry: './src/index.js',
  externals: ['lodash'],
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'library.js',
    library: 'root',
    libraryTarget: 'umd'
  }
}

externals 会在打包的过程当中,假如遇到了 lodash 这个库,就不会打包进去,能够写成数组情势也能够是字符串,更改完后再次打包

《24 个实例入门并控制「Webpack4」(二)》

能够发明我们库里运用的 lodash 并没有被打包进去,体积只要 1kb

这个时刻他人再次运用我们的 library 这个库,假如不引入 lodash,则会失利,他人在运用 library 之前要先引入 lodash

假如改成 externals: 'lodash',则运用的时刻为,import lodash from lodash,而不能用 _ 下划线来替代 lodash, import _ from lodash

假如要让他人运用你的库,着实就是运用你打包后的文件,需要先在 package.json,将 main: index.js 改成 main: ./dist/library.js,经由过程 npm 宣布之前,你要确保你的库的 name 不会和他人上线的 name 争执,改一个有特性的 name,来确保能宣布胜利,如 library-xh-2019,感兴趣的能够本身去研究一下怎样经由过程 npm 宣布

{
  "name": "library-xh-2019",
  "version": "1.0.0",
  "description": "",
  "main": "./dist/library.js",
  "scripts": {
    "build": "webpack"
  },
  "keywords": [],
  "author": "xh",
  "license": "MIT",
  "devDependencies": {
    "webpack": "^4.29.6",
    "webpack-cli": "^3.3.0"
  },
  "dependencies": {
    "lodash": "^4.17.11"
  }
}

个人博客

24 个实例入门并掌握「Webpack4」(一)

24 个实例入门并掌握「Webpack4」(三)

    原文作者:ITxiaohao
    原文地址: https://segmentfault.com/a/1190000019132609
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞