本文最后更新于 2024-03-14,文章内容可能已经过时。

Webpack: 是一个前端资源加载/打包工具。它将根据模块的依赖关系进行静态分析,然后将这些模块按照指定的规则生成对应的静态资源。
为了简化开发的复杂度,前端社区涌现出了很多好的实践方法:模块化,让我们可以把复杂的程序细化为小的文件;
类似于TypeScript这种在JavaScript基础上拓展的开发语言:使我们能够实现目前版本的JavaScript不能直接使用的特性,并且之后还能转换为JavaScript文件使浏览器可以识别;Scss,less等CSS预处理器
因此,Webpack就是可以分析你的项目结构,找到JavaScript模块以及其它的一些浏览器不能直接运行的拓展语言(Scss,TypeScript等),并将其打包为合适的格式以供浏览器使用.

webpack概念

webpack 是一个现代 JavaScript 应用程序的静态模块打包器(module bundler)。当 webpack 处理应用程序时,它会递归地构建一个依赖关系图(dependency graph),其中包含应用程序需要的每个模块,然后将所有这些模块打包成一个或多个 bundle。

打包工具

  • JavaScript 模块打包之后就可以运行在浏览器

能做什么

  • webpack 可以当作是一个模块打包平台,但是它本身只能打包 JavaScript 模块

  • 对于其它的文件模块资源,则需要使用第三方 loader 来处理

  • JavaScript 资源打包

  • css 打包

  • 图片 打包

  • less

  • sass

  • babel EcmaScript 6 转 EcmaScript 5

  • 开发工具:http 服务器

  • 代码改变,自动刷新浏览器

  • 压缩代码

  • JavaScript 代码压缩

  • html 代码压缩

  • css 代码压缩

核心概念

  • Entry

  • Output

  • Loaders

  • Plugins

  • Mode

  • Browser Compatibility

其它打包工具

相关资源链接

配置webpack第三方包

通常情况下我们不打包第三方包,因为第三方包太大,和 bundle 打包到一起会造成资源体积过大,所以我们还是通过 script 标签的方式把第三方资源引入到页面中,只需要通过以下配置即可,这里以 jQuery 为例

  1. 下载第三方包

npm i jquery
  1. 在页面中引入资源

<script src="node_modules/jquery/dist/jquery.js"></script>
  1. 配置

externals: {
  // key 是第三方包名称,value 是全局中的 jQuery 对象
  // 这里配置的含义就是:当你在代码中 import jquery 的时候,不会把 jquery 打包到 bundle 中,而是使用我指定的全局中的 jQuery 对象
  jquery: 'jQuery'
}
  1. 加载使用

import $ from 'jquery'

$('#app', {
  width: 200,
  height: 200,
  backgroundColor: 'pink'
})
  1. 打包测试

npm run build

webpack 基础

javascript 模块化

整个web的发展越来越快,涉及到的东西以及要处理的越来越多,于是我们的JS代码就越来越大,自然越来越混乱,就容易出错。因此,我们把代码阉割了。嗯,没错,就是我们把这个大西瓜切成很多块,所以每个程序员都可以自己选择一块,然后吃一块,不再是一个大西瓜一人吃一口了

  • Node.js(服务端)

  • AMD 模块规范(用于浏览器)

    • <span style="color:#fd7275"> require.js 库 </span>

  • CMD 模块规范(用于浏览器)

    • <span style="color:#fd7275"> sea.js 库 </span>

  • ECMAScript 6 模块规范

webpack 模拟

准备
  1. 创建 webpack-demos 学习目录

  2. 创建 webpack-demos/src 目录

  3. src 目录中分别创建以下两个文件

import example from './example'

example()

export default function () {
  console.log('Hello webpack!')
}

  1. 创建 webpack-demos/index.html 文件

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Document</title>
</head>
<body>
  <h1>Hello webpack!</h1>
  <!-- 浏览器无法直接运行模块源码 -->
  <!-- <script src="src/index.js"></script> -->
</body>
</html>
webpack 打包
  1. 创建package.json文件
    npm init
    npm init -y
    形成 package.json 文件

Wrote to c:\Users\lenovo\Desktop\webpack-dome\package.json:

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

2 安装依赖

npm i -D webpack webpack-cli 

3 打包命令

npx webpack 

包的调用的方式:
① 引用API ② 命令的方式使用
npx 会找到项目中安装的 webpack 或者全局的 webpack。

4 webpack 运行过程

  • 默认找到 src/index.js

  • 分析 src/index.js 所有的依赖

  • 然后将打包结果输出到 dist/mian.js 中

使用配置文件

创建webpack.config.js文件

const path = require('path')

module.exports = {
  entry: './src/index.js', // 打包的入口
  output: {
    path: path.join(__dirname, './dist'),  // 将打包结果放到 dist 目录中
    filename: 'main.js' // 自定打包结果的文件名
  }
}
执行打包
npx webpack --config webpack.config.js
> npm run build #执行命令

配置 npm scripts

  • 方式1

./node_module/.bin/webpack

-方式2

npx webpack

-方式3 <span style="color:#fd7275">(使用)</span>

{
 "name": "webpack-demos",
 "version": "1.0.0",
 "description": "",
 "main": "index.js",
 "scripts": {
   "test": "echo \"Error: no test specified\" && exit 1",
   "build": "webpack --config webpack.config.js" //npn run build
 },
 "keywords": [],
 "author": "",
 "license": "ISC",
 "devDependencies": {
   "@babel/core": "^7.4.5",
   "@babel/preset-env": "^7.4.5",
   "babel-loader": "^8.0.6",
   "clean-webpack-plugin": "^3.0.0",
   "css-loader": "^3.0.0",
   "file-loader": "^4.0.0",
   "html-webpack-plugin": "^3.2.0",
   "less": "^3.9.0",
   "less-loader": "^5.0.0",
   "style-loader": "^0.23.1",
   "webpack": "^4.35.2",
   "webpack-cli": "^3.3.5"
 }
}

javascript 模块打包

模块概念

在模块化编程中,开发人员将程序分解为称为模块的离散功能块,每个模块的表面积小于完整程序,使验证,调试和测试变得微不足道。编写良好的模块提供了可靠的抽象和封装边界,因此每个模块在整个应用程序中具有一致的设计和明确的目的。

什么是webpack模块

<span style="color:#fd7275">webpack 模块可以以各种方式表达它们的依赖关系</span>
-一个ES2015import声明
-一个CommonJS的 require()声明
-一个AMD define和require声明
-css / sass / less文件中的@import语句。
-样式表(url(...))或html(<img src=...>)文件中的图像URL 。

webpack 打包模式

//mode : 'none||production || development (默认) '

module.exports = {
  mode: 'production'
};

  • production 模式打包 上线适合

  • development 开发模式打包 开发适合

  • 如何没有配置会有警告,默认是development

webpack 打包css

安装两个样式包 style-loader css-loader

> npm install --save-dev style-loader css-loader 

打包规则:

  const path = require('path');

  module.exports = {
    entry: './src/index.js',
    output: {
      filename: 'bundle.js',
      path: path.resolve(__dirname, 'dist')
    },
+   module: {
+     rules: [
+       {
+         test: /\.css$/,
+         use: [
+           'style-loader',
+           'css-loader'
+         ]
+       }
+     ]
+   }
  };

打包测试:
1项目 添加样式

|- /src
+   |- style.css
    |- index.js

2添加 SRC / style.css文件

.hello {
  color: red;
}

3 添加 SRC / index.js 文件

+ import './style.css';
+   element.classList.add('hello');

4 测试

npm run build

...
    Asset      Size  Chunks             Chunk Names
bundle.js  76.4 KiB       0  [emitted]  main
Entrypoint main = bundle.js
...

webpack 打包图片

添加依赖 :npm install --save-dev file-loader
配置webpack.config.js 文件

    module: {
      rules: [
        {
+         test: /\.(png|svg|jpg|gif)$/,
+         use: [
+           'file-loader'
          ]
    }
      ]
    }
  };

添加 一张图片

 |- /src
+   |- icon.png

添加引用 SRC / index.js

+ import Icon from './icon.png'; 

+   // Add the image to our existing div.
+   const myIcon = new Image();
+   myIcon.src = Icon;
+
+   element.appendChild(myIcon);

在css 中添加图片 SRC / style.css文件

+   background: url('./icon.png'); 

合并命令

npm run build

...
                               Asset      Size  Chunks                    Chunk Names
da4574bb234ddc4bb47cbe1ca4b20303.png  3.01 MiB          [emitted]  [big]
                           bundle.js  76.7 KiB       0  [emitted]         main
Entrypoint main = bundle.js
...

webpack 打包html

设置HtmlWebpackPlugin

安装依赖:npm install --save-dev html-webpack-plugin

const HtmlWebpackPlugin = require('html-webpack-plugin'); 

new CleanWebpackPlugin(),// 打包前先清理dist目录文件 
  plugins: [
+     new HtmlWebpackPlugin({
+      template:'html文件路径'
       minify: {
       removeComments:true, //删除注释
       cokkapseWhitespace:ture //压缩
       }
+     })
+   ],

清理dist 文件

HtmlWebpackPlugin默认情况下会生成自己的index.html文件,即使dist/文件夹中已有文件也是如此。这意味着它将index.html用新生成的文件替换我们的文件。 && 通常,/dist在每次构建之前清理文件夹是一种很好的做法,这样只会生成使用过的文件。让我们来处理。
new CleanWebpackPlugin(),// 打包前先清理dist目录文件

添加依赖clean-webpack-plugin
npm install --save-dev clean-webpack-plugin
添加 webpack.config.js

const { CleanWebpackPlugin } = require('clean-webpack-plugin');
new CleanWebpackPlugin(),  // plugins: 

webpack 字体文件

更新 webpack.config.js

+       {
+         test: /\.(woff|woff2|eot|ttf|otf)$/,
+         use: [
+           'file-loader'
+         ]
+       }

添加文件 my-font.woff my-font.woff2

|- /src
+   |- my-font.woff
+   |-  

更新文件 SRC / style.css文件

+ @font-face {
+   font-family: 'MyFont';
+   src:  url('./my-font.woff2') format('woff2'),
+         url('./my-font.woff') format('woff');
+   font-weight: 600;
+   font-style: normal;
+ }
 

webpack 打包less文件

添加依赖 $ npm install less-loader --save-dev
更新文件 webpack.config.js

module.exports = {
  module: {
    rules: [
      {
        test: /\.less$/,
        loader: 'less-loader', // 将 less 转为 css,less-loader 依赖了 less
      },
    ],
  },
};

webpack ES6-ES5

安装依赖: npm i -D babel-loader @babel/core @babel/preset-env
添加文件 :

module: {
  rules: [
    {
      test: /\.m?js$/,
      exclude: /(node_modules|bower_components)/,
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env']
        }
      }
    }
  ]
}

更多更新


配置babel-polyfill

SourceMap

自动检索编译构建

Using webpack-dev-sever 服务器

配置热更新


高级概念


webpack 和 Vue


webpack 和 React

01 webpack流程化安装

主要是为了熟悉react的目录结构,指令什么的,以及一些基础的webpack,会有很多配置的东西

01创建目录

mkdir react-demo // 新建项目文件夹
cd react-demo // cd到项目目录下
npm init // npm初始化

webpack 的一些操作

npm i  webpack webpack-cli --save--dev
touch webpack.config.js

webpack配置文件

/*
 * @Descripttion:  webpack.config.js 
 * @version:  ON||FOR
 * @@Company: DCIT-SH
 * @Author: Oneself
 * @Date: 2020-11-27 16:37:06
 * @LastEditors: Oneself
 * @LastEditTime: 2020-11-27 16:39:44
 * @Statu: TODO:    webpack配置文件 
 */
const path = require('path');
module.exports = {
  entry: './src/app.js', // 入口文件
  output: {
    path: path.resolve(__dirname, 'dist'), // 定义输出目录
    filename: 'bundle.js'  // 定义输出文件名称
  }
};

package.json 添加webpack执行命令

"scripts": {
  "build": "webpack --config webpack.config.js"
}

因为我们的入口文件是'./src/app.js',而我们执行build的时候会先到入口文件,我感觉的这个就像是thinkphp或者一些后端框架的 index.php,或者admin.php (意思上)而现在我们并没有入口文件,创建src目录,创建app.js

npm run build

在我们的根目下会生成一个dist目录,一个bundle.js

02webpack-dev-server
webpack-dev-server是一个小型的node.js Express服务器,它使用webpack-dev-middleware中间件来为通过webpack打包生成的资源文件提供Web服务。

npm install --save-dev webpack-dev-server

package.json 更新命令

"scripts": {
    "dev":"webpack-dev-server"
}

添加配置
webpack.config.js新增devServer配置

devServer: {
  hot: true, // 热替换
  contentBase: path.join(__dirname, 'dist'), // server文件的根目录
  progress:true,//开启进度条
  compress: true, // 开启gzip
 //open:true, //自动打开浏览器,
  port: 8080, // 端口
},

报错 Cannot find module 'webpack-cli/bin/config-yargs'
这个错误格外的眼熟,刚学webpack时候就遇到过,
package.json 改成如下版本
方法1:前提是你知道你依赖的版本

"webpack-dev-server": "^依赖版本"
删除node_modules文件夹
npm i 

方法2:最新版本

npm uninstall webpack-dev-server -g       卸载全局
npm uninstall webpack-dev-server -D      卸载局部(本地) 
npm install webpack-dev-server --save-dev      最新

方法3 看下以前项目的启动版本

 npm i webpack@4.43.0 webpack-cli@3.3.12 webpack-dev-server@3.11.0 webpack-dev-server -D

麻蛋的又报错了

Error: spawn cmd.exe ENOENT

看到这个错误的时候,我们就要考虑下, cmd.exe
定位错误的话,应该是我们的电脑问题,一般是环境变量,
在后端的日常中,我们会调用一些exe程序进行加密,拆解,拼图,会因为你的exe文件没有配置到电脑的环境变量,而找不到程序,
我查了下 cmd.exe是用户环境变量中加入System32
添加环境变量
cmd.exe 在哪个文件夹

C:\Windows\System32
还是不行,我百度了下,需要重启下电脑。我坲了

OK重启后可以正常启动

03安装 HtmlWebPackPlugin
说白就是html生成器,HTML模板插件 让webpack 简化了HTML文件的创建
HtmlWebPackPlugin
为html文件中引入的外部资源如script、link动态添加每次compile后的hash,防止引用缓存的外部文件问题
可以生成创建html入口文件,比如单页面可以生成一个html文件入口,配置N个html-webpack-plugin可以生成N个页面入口

npm install --save-dev html-webpack-plugin

webpack.config.js 添加配置 添加在 module.exports

// 引入html插件文件
const HtmlWebPackPlugin = require('html-webpack-plugin');
---------------------------
plugins: [
  new HtmlWebPackPlugin({
    // template是模板文件需要我们创建 
    template: './public/index.html',
    filename: path.resolve(__dirname, 'dist/index.html'),
    minify: {
                //true不换行
                collapseWhitespace: true
            },
    hash: true //生产环境下生成hash戳
  })
]
 npm run dev 

多页面应用,我在网上看的时候,这个东西用的不是很多,但是有些面试题会问,多页面应用说白了就是多个入口,和后端那些框架的设计模式差不多,
webpack.config.js

module.exports = {
// 多入文件
    entry: {
        index: "./src/index.js", // 前台入口 
        admin: "./src/admin.js"  // 后台入口
    },
    output: {
        path: path.resolve(__dirname, 'dist'), // 定义输出目录
        filename: '[name].js',  // 定义输出文件名称  [name]自动获取入口的home和admin, 将entry中的键提取出来
        publicPath: "/"  //build之后的公共路径
    },
     plugins: [
        new HtmlWebPackPlugin({
            // template是模板文件需要我们创建 
            template: './public/index.html',
            filename: path.resolve(__dirname, 'dist/index.html'),
            chunks:['index'],//只引用index.js,解决index.html里面有index.js和admin.js的问题
            minify: {
                //折叠换行true不换行
                collapseWhitespace: true
            },
            hash: true //生产环境下生成hash戳

        }),
        new HtmlWebPackPlugin({
            // template是模板文件需要我们创建 
            template: './public/admin.html',
            filename: path.resolve(__dirname, 'dist/admin.html'),
            chunks:['admin'],//只引用index.js,解决index.html里面有index.js和admin.js的问题
            minify: {
                //折叠换行true不换行
                collapseWhitespace: true
            },
            hash: true //生产环境下生成hash戳
        })
    ]
}

感觉我注释写的很清楚了,简单的说就是添加几个辨别项,将单页面转化为多页面,记得根据入口文件新建文件entry下现在是两个入口文件

 npm run build

在我们指定的目录下会生成dist index.js index.html ,admin.js admin.js 但是我看到了警告,

WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/

ε=(´ο`*)))唉,我给忘了一个mode,虽然不印象打包,但是还是看着挺难受的,在 module.exports中配置

 //模式 默认两种production(生产环境:代码压缩) development(开发环境:代码不压缩)
    mode: "development",

04loaders 配置css

npm install --save-dev css-loader style-loader mini-css-extract-plugin

css-loader:解析@import这种语法
style-loader:把css插入到head标签中
mini-css-extract-plugin:抽离css样式让index.html里面的css样式变成link引入

配置 webpack.config.js

let MiniCssExtractPlugin = require("mini-css-extract-plugin"); 
// 在插件中引用 
plugins: [
 new MiniCssExtractPlugin({
      filename: "static/css/main.css",
    }),
]
// 在模块中,配置不同的规则 
  module: {
    //规则
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader, //都放到了上面的main.css里面
          {
            loader: "css-loader",
          },
        ],
      },
    ],
  },

然后我们测试下,看看是否将css引用了,在src目录下新建assets目录,新建两个css文件,在index.js中

@import '你放置css的位置'
npm run dev 
/*就会发现,你写的css已经加载到css中了, @import也可以在css中使用,将公共的类,和当前css*/
npm run build
/*就会生成对应配置的目录结构 .  static/css/main.css

css兼容性处理

npm install --save postcss-loader autoprefixer

05配置 css 兼容性 webpack.config.js

// 在css 规则 中添加 一个新的postcss-loader规则 写在css配置的use中 
{ loader: "postcss-loader" },

在根目录下新建 postcss.config.js 配置浏览器建兼容

module.exports = {
    plugins: {
        'autoprefixer': {
          overrideBrowserslist: [
            "Android 4.1",
            "iOS 7.1",
            "Chrome > 31",
            "ff > 31",
            "ie >= 8"
          ]
        }
    }
};

打包后查看我们的dist文件夹下css,自动生成css文件

    -webkit-transform: rotate(60deg);
        -ms-transform: rotate(60deg);
            transform: rotate(60deg);

webpack.config.js 配置会越来越大,位置会越来越多,建议学习下 webpack

06配置 css 压缩

npm install --save optimize-css-assets-webpack-plugin

//引入css压缩
let OptimizeCss = require("optimize-css-assets-webpack-plugin");
// 添加配置 
 optimization: {
    minimizer: [
      new OptimizeCss(), //优化css
    ],
  },

需要配置mode模式
07配置 js 压缩

npm install --save uglifyjs-webpack-plugin
//js压缩
let UglifyjsPlugin=require('uglifyjs-webpack-plugin');
minimizer: [
        //压缩js    
        new UglifyjsPlugin({
                cache:true, //是否用缓存
                parallel:true, //是否并发打包
                sourceMap:true //es6映射es5需要用
            }), 
]

08配置图片

npm install --save-dev url-loader

// 配置 
module:{
      rules: [       
         {
                test:/\.(png|jpg|gif|jpeg)$/,
                use:{
                    loader:"url-loader", //file-loader加载图片,url-loader图片小于多少k用base64显示
                    options: {
                        limit:100*1024, //小于100k用base64
                        //build之后的目录分类
                        outputPath:'static/images'                    },
                }
            },
       ]
}

09es6转es5 配置

npm install --save babel-loader @babel/core @babel/preset-env @babel/plugin-proposal-class-properties @babel/plugin-transform-runtime @babel/runtime

10安装react

npm i react react-dom --save
npm i babel-preset-react --save-dev

安装babe

npm install babel-loader@next @babel/core @babel/preset-react @babel/runtime --save
Babel 是一个 JavaScript 编译器 (说白就是为了解析js代码)

Babel 是一个工具链,主要用于将 ECMAScript 2015+ 版本的代码转换为向后兼容的 JavaScript 语法,以便能够运行在当前和旧版本的浏览器或其他环境中。下面列出的是 Babel 能为你做的事情:

  • 语法转换

  • 通过 Polyfill 方式在目标环境中添加缺失的特性 (通过 @babel/polyfill 模块)

  • 源码转换 (codemods)
    更新webpack.config.js

 module: {
    rules: [
      {
        test: /\.(js | jsx)$/, // 因为react是jsx,需要添加jsx
        exclude: /node_modules/,
        use: {
          loader: "babel-loader",
        },
      },
    ],
  },

{
    "presets": ["@babel/preset-env", "@babel/preset-react"]
}

更新index.js

import React from "react";
import ReactDOM from "react-dom";

class App extends React.Component{
    render(){
        return(
            <div>Hello React!</div>
    )
    }
}
export default App;

ReactDOM.render(<App />, document.getElementById("app"));

将index.js ReactDOM.render(<App />, document.getElementById("app")); 抛出的节点绑定到文件流中
更新public/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title> 首页 </title>
</head>
<body>
    <div id="app">
        
    </div>
   
</body>
</html>

webpack 和 Angular


webpack 性能优化


webpack 底层原理