IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> JavaScript知识库 -> webpack -> 正文阅读

[JavaScript知识库]webpack

什么是webpack

本质上,webpack 是一个用于现代 JavaScript 应用程序的 静态模块打包工具 。当 webpack 处理应用程序时,它会在内部从一个或多个入口点构建一个 依赖图 ,然后将你项目中所需的每一个模块组合成一个或多个 bundles ,它们均为静态资源,用于展示你的内容

  • 打包: 将不同类型的资源按模块处理进行打包
  • 静态:打包最终产出静态资源
  • 模块:webpack 支持不同规范的模块化开发,如 ES Module、CommonJS 等可同时使用

安装 webpack

注意:全局安装可以直接使用 webpack 命令打包,但不推荐,避免将项目中的 webpack 锁定到指定版本,并且在使用不同的 webpack 版本的项目中, 可能会导致构建失败。

1、安装 webpack 和 webpack-cli, webpack-cli 是在 node 下运行所必须的

mkdir webpack-demo
cd webpack-demo
npm init -y
npm install webpack webpack-cli --save-dev

2、修改 package.json,增加"build": "webpack"

这里可以自行设置入口和出口,如 webpack --entry ./src/main.js --output-path ./build

{
  "name": "learn-webpack",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack"
  },
  "keywords": [],
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "webpack": "^5.65.0",
    "webpack-cli": "^4.9.1"
  }
}

3、运行 webpack 进行打包

npm run build

CSS loader

为什么需要 loader

默认情况下无法处理 css 、 less 文件,需要对文件进行转换,loader 就是起到一个转换的作用

css-loader 、 style-loader 、less-loader

css 并非 js 模块, 需要使用 css-loader 识别模块并解析出依赖关系, style-loader 才可以解析并生成样式

安装 css-loader 、 style-loader 、 less-loader

npm i css-loader -D
npm i style-loader -D
npm i less-loader -D

行内 css-loader

import "css-loader!../css/example.css";

配置文件中使用 css-loader 、 style-loader 、和 less-loader

webpack.config.js

const path = require("path");
module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "main.js",
    path: path.resolve(__dirname, "dist"),
  },

  module: {
    rules: [
      {
        test: /\.css$/, // 一般是匹配我们所需要处理的文件类型正则表达式
        use: [
          // 注意顺序,需先添加 style-loader 才能解析样式
          // 按从上往下或从右往左顺序执行
          // 未配置 options 可简写未 use: ['style-loader', 'css-loader']
          {
            loader: "style-loader",
          },
          {
            loader: "css-loader",
          },
        ],
      },
      // 下面采用简写方式
      {
        test: /\.less$/,
        // 这里还是需要添加 css-loader
        use: ["style-loader", "css-loader", "less-loader"],
      },
    ],
  },
};

browserslistrc

为什么需要 browserslistrc

目前前端开发均采用工程化方式,不仅需要考虑对各类工具包的兼容性,需要考虑浏览器对 CSS 语法、 JS 语法的兼容性,browserslistrc 可以帮助我们完成目标环境配置。 browserslist 单独是没用的,需要结合 bable 、 autoprefixer 等工具来确定需转译的 JS 特性和需要添加的 CSS 浏览器前缀。它的查询数据来源于 Can I Use

配置 browserslistrc

package.json 增加如下代码,表示兼容市场占有率大于 1% 或最新两个版本或最近24个月有更新维护的浏览器

{
  "browserslist": [
    ">1%",
    "last 2 versions",
    "not dead",
    "not ie <= 8"
  ]
}

添加 .browerslistrc 配置文件书写如下代码

> 1%
last 2 versions
not dead
not ie <= 8

postcss

一个通过 JS 来转换样式的工具,以达到兼容性

安装 postcss

要在命令行中使用 postcss 还需安装 postcss-cli ,并安装 autoprefixer 添加前缀,最后生成待前缀的 css

npm i postcss -D
npm i postcss-cli -D
npx i autoprefixer -D
npx postcss --use autoprefixer  -o ret.css ./src/css/test.css

postcss-loader

应该放在 css-loader 之前加载,以加上前缀

{
  loader: "postcss-loader",
    options: {
    postcssOptions: {
      // plugins: [require("autoprefixer")],
      // postcss-preset-env 是一个预设——插件集合
      // 包含了autoprefixer,支持简写,当然 autoprefixer 也支持简写
      plugins: ["postcss-preset-env"],
    },
  }
}
// 顺序 [style-loader, css-loader, postcss-loader]

importLoaders 属性

在一个 css 文件中导入另一个 css 文件来使用其中的样式时,由于 css 被匹配到后 postcss-loader 先进行工作添加前缀,然后再把代码传递给 css-loader , css-loader 可以处理 @import 导入的内容或者 @import meida 、 url 之类的内容,但并不会再回头交给 postcss-loader 处理,而是直接交给 style-loader 进行展示,这样我们就需要用到 importLoaders 属性指定配置的 css-loader 作用于 @import 的资源之前有多少个 loader

{
  loader: "css-loader",
  options: {
    importLoaders: 1,
  },
}

File loader

安装 file-load

npm i file-load -d

使用 file-load

使用 file-loader 会在 /dist 目录中生成导出的图片,他会把文件名称、路径返回并拷贝到打包目录,还要分开请求图片,请求次数变多

img 标签中的图片

// 添加图片
function pckImg() {
  const oEle = document.createElement("div");
  const oImg = document.createElement("img");
  oImg.src = require("../img/webpack.png").default; // webpack5 得加 default
  oEle.appendChild(oImg);
  return oEle;
}

document.body.appendChild(pckImg());

// 配置 webpack rules
{
test: /\.(png|svg|gif|jpg|jpeg)$/,
use: ["file-loader"],
},

// 不使用 .default 的方法一
use: [
  {
    loader: "file-loader",
    options: {
      esModule: false, // 是否将导出的内容转为 esModule
    },
  },
],

// 不使用 .default 的方法二
import oImgSrc from "../img/webpack.png"
function pckImg() {
  const oEle = document.createElement("div");
  const oImg = document.createElement("img");
  oImg.src = oImgSrc;
  oEle.appendChild(oImg);
  return oEle;
}
document.body.appendChild(pckImg());

背景图片

// 添加盒子及 css
import "../css/img.css";
function pckImg() {
  const oEle = document.createElement("div");
  oEle.className = "bgBox";
  return oEle;
}

document.body.appendChild(pckImg());

// 添加 file-loader
{
  test: /\.(png|svg|gif|jpg|jpeg)$/,
  use: [
    {
      loader: "file-loader",
      options: {
        esModule: false, // 是否将导出的内容转为 esModule
      },
    }
  ],
},

// 修改 css-loader, 如果不修改 esModule 属性为 false 同样会无法识别
// 需要添加 default, 但 css 不会允许那么去写
{
  loader: "css-loader",
  options: {
    esModule: false, // 是否将导出的内容转为 esModule
  },
},

设置图片名称于输出

文件名称占位符

  • [ext]:扩展名

  • [name]:文件名

  • [hash]:结合文件内容产生 hash

  • [contentHash]:在 file-loader 中于 作用一样

  • [hash: length]

  • [path]:路径,相对 webpack 配置文件

{
  loader: "file-loader",
  options: {
   esModule: false,
   // 文件名称
   name: "[name].[hash:6].[ext]",
   // 输出路径
   outputPath: 'img'
   // 简写 name: "img/[name].[hash:6].[ext]",
  },
}

url-loader

安装 url-loader

npm i url-loader -D

使用 url-loader

使用 url-loader 不会在 /dist 目录中生成导出的图片,而是以 base64URL 的方式加载到我们的资源中,减少请求次数。 url-loader 内部也可以调用 file-loader ,通过 limit 控制使用哪种方法

// 和 fileloader 用法一样, 还是要给 css loader 设置 esModule 属性为 false
{
  test: /\.(png|svg|gif|jpg|jpeg)$/,
  use: [
    {
      loader: "url-loader",
      options: {
        esModule: false,
        name: "img/[name].[hash:6].[ext]",
        limit: 25 * 1024,  // 25KB, 超过25KB会交给 file-loader 处理,拷贝出来
      },
    },
  ],
}

base64URL:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Cb2vy3Ri-1642001847935)(C:\Users\HeHao\AppData\Roaming\Typora\typora-user-images\image-20220104222133104.png)]

asset 资源模块(webpack5)

webpack5 后可以直接使用资源类型模块 asset module type 来简化 loader 的使用或替换,无需额外安装, webpack5 已内置

四个 asset 资源模块

  • asset/resource ===> file-loader

  • asset/inline ===> url-loader

  • asset/source ===> raw-loader

  • asset

基本使用

{
  test: /\.(png|svg|gif|jpe?g)$/,
  type: "asset/resource",
}

设置 asset 指定输出目录

方法一:设置 output 的 assetModuleFilename 属性

const path = require("path");
module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "main.js",
    path: path.resolve(__dirname, "dist"),
    assetModuleFilename: "img/[name].[hash:6][ext]", // 这里有点区别,文件后最无需加.
  },

  module: {
    rules: [
      {
        test: /\.(png|svg|gif|jpe?g)$/,
        type: "asset/resource",
      },
    ],
  },
};

**缺点:**会把字体等资源也输出到 img 文件夹中

方法二:设置 rule 的 generator 属性

const path = require("path");
module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "main.js",
    path: path.resolve(__dirname, "dist"),
  },

  module: {
    rules: [
      {
        test: /\.(png|svg|gif|jpe?g)$/,
        type: "asset/resource",
        generator: {
            filename: "img/[name].[hash:6][ext]"
        }
      },
    ],
  },
};

根据文件大小阈值选择

使用 asset , 添加 parser

{
  test: /\.(png|svg|gif|jpe?g)$/,
  type: "asset",
  generator: {
    filename: "img/[name].[hash:6][ext]"
  },
  parser: {
  	dataUrlCondition: {
      maxSize: 20 *1024,
  	}
  }
}

字体图标处理

{
  test:  /\.(ttf|eot|svg|woff2?)$/,
  type: "asset/resource", // 也可以使用 inline 以Base64URL方式打包到 js ,但不能加 generator
  generator: {
    filename: "font/[name].[hash:3][ext]",
  },
},

webpack 插件

loader 和 plugin 的区别

loader:在读取特定内容时,对特定文件类型进行转换

plugin:使用灵活,贯穿 webpack 的整个生命周期,比 loader 可以做的事情更多

插件的本质上是一个类,有自己的构造函数和 apply 方法

第一个插件 —— clean-webpack-plugin

第三方插件,每次打包清空 /dist 目录

安装 clean-webpack-plugin

npm i clean-webpack-plugin -D

使用插件

webpack.config.js

// 引入插件
const { CleanWebpackPlugin } = require("clean-webpack-plugin");

// 使用插件
module.exports = {
    
  entry: "./src/index.js",
    
  output: {
    filename: "main.js",
    path: path.resolve(__dirname, "dist"),
  },

  module: {
      ...
  },
	
  plugins: [new CleanWebpackPlugin()], // 调用插件
};

html-webpack-plugin 和 DefinePlugin

自定义 index.html 配置到 ./public 目录

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="gb2312" />
    <!-- 常量占位 DefinePlugin -->
    <link rel="icon" href="<%= BASE_URL %>" />
    <title>
      <!-- 对象属性占位 html-webpack-plugin -->
      <%= htmlWebpackPlugin.options.title %>
    </title>
  </head>
  <body>
    <script src="./dist/main.js"></script>
  </body>
</html>

webpack.config.js

// 引入插件
const {DefinePlugin} = require("webpack");  // webpackb内置插件
const HtmlWebpackPlugin = require("html-webpack-plugin");

// 添加插件配置
plugins: [
  new CleanWebpackPlugin(),
  new HtmlWebpackPlugin({
    title: "webpack 快速上手",
    template: "./public/index.html", // 存放自己的静态资源
  }),
  new DefinePlugin({
    // 常量写这里
    BASE_URL:
      // 这里必须用双层引号,否则打包的文件路径不会是字符串,引发 Unexpected token 错误
      '"https://webpack.docschina.org/favicon.f326220248556af65f41.ico"',
  }),
],

copy-webpack-plugin

可以使用它拷贝文件到 ./dist 目录

安装 copy-webpack-plugin

npm i copy-webpack-plugin -D

使用 copy-webpack-plugin

const CopyWebpackPlugin = require("copy-webpack-plugin");

  plugins: [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
      title: "webpack 快速上手",
      template: "./public/index.html",
    }),
    new DefinePlugin({
      BASE_URL:
        '"https://webpack.docschina.org/favicon.f326220248556af65f41.ico"',
    }),
    new CopyWebpackPlugin({
      // 需拷贝的配置项
      patterns: [
        {
          from: "public", // 从哪里 copy
          // to: '', 这里可以省略 to,自动从 output 的 path 去找
          globOptions: {
            ignore: ['**/index.html'] 
              // 这里必须在前面加 **/ 表示从当前路径下忽略
              // 且忽略目录中文件后不能为空
          }
        },
      ],
    }),
  ],

babel-loader

babel

为什么需要babel

将 JSX TS ES6+ 转换成浏览器平台可以直接使用的代码

安装 babel core 和 babel cli

npm i @babel/core -D
npm i @babel/cli -D

npm i @babel/plugin-transform-arrow-functions -D
npm i @babel/plugin-transform-block-scoping -D

使用 babel

babel core 需要结合具体的转换插件才能转换为其他兼容性代码。将 ./src 中的所有 js 代码进行箭头函数和作用域转换,转换的文件放到 ./bulid 目录中

npx babel src --out-dir build --plugins=@babel/plugin-transform-arrow-functions,@babel/plugin-transform-block-scoping

使用 babel 预设

安装预设,避免麻烦的单独安装和调用

npm i @babel/preset-env -D

使用预设,将 ./src 中的所有 js 代码使用预设进行转换,转换的文件放到 ./bulid 目录中

npx babel src --out-dir build --presets=@babel/preset-env 

babel-loader

安装 babel-loader

npm i babel-loader -D

使用 babel-loader

{
  test: /\.js$/,
  use: [
    {
      loader: "babel-loader",
      options: {
      	// 使用插件
        // plugins: [
        //   "@babel/plugin-transform-arrow-functions",
        //   "@babel/plugin-transform-block-scoping",
        // ],
        // 使用预设
        presets: ["@babel/preset-env"],
      },
    },
  ],
}

给 babel-loader 指定兼容浏览器

1、根据 browserslistrc 的配置(推荐,但主要是用于 postcss)

2、配置targets,与 browserslistrc 同时存在优先使用该配置

{
  test: /\.js$/,
  use: [
    {
      loader: "babel-loader",
      options: {
        // plugins: [
        //   "@babel/plugin-transform-arrow-functions",
        //   "@babel/plugin-transform-block-scoping",
        // ],
        presets: [
          [
            "@babel/preset-env",
            {
              targets: "chrome 91",
            },
          ],
        ],
      },
    },
  ],
}

babel-loader 相关配置文件(推荐方法)

简化 babel-loader 配置,避免深层嵌套

  • 现在推荐使用:babel.config.js 或json cjs mjs

  • babel7之前推荐使用:babelrc.json 或js mjs cjs 或直接 .babelrc

module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        targets: "chrome 91",
      },
    ],
  ],
};

polyfill

polyfill 是什么

在遇到 Promise 、 generator 、 symbol 等一些更新语法时 @babel/preset-env 还是无法帮助我们进行转换,所有这个时候需要用到 polyfill 。 注意,在webpack4 默认加入 polyfill 导致产出文件特别大, webpack5 基于优化打包速度考虑已默认移除。

安装 polyfill

这里应该安装为生产依赖,因为生产环境下同样需要依赖它进行转化(babel 7.4.0 开始已被弃用)

npm i @babel/polyfill --save

但是整体来说 @babel/polyfill 包还是过大,如果只需要转换 已正式发布的 ECMAScript 标准进行转换,只需要安装 core-js/stable 和 regenerator-runtime/runtime (转换生成器函数) 两个包即可。

npm i core-js regenerator-runtime

配置 polyfill

在 js 入口文件引入两个包

import "core-js/stable";
import "regenerator-runtime/runtime";

作为 babel 的工具使用,配置babel.config.js

module.exports = {
  presets: [
    [
      "@babel/preset-env",
      {
        // 三个值,不写默认 false ,不对当前 JS 处理做 polyfill 的填充
        // usage:依据用户源代码中使用到的新语法进行填充
        // entry:依据需要兼容的浏览器进行填充
        useBuiltIns: "usage",
        corejs: 3,
      },
    ],
  ],
};

webpack.config.js 的 js 规则中加入 exclude: /node_modules/ ,因为部分使用的 node_modules 本身已经做了 polyfill ,应该排除

{
  test: /\.js$/,
  exclude: /node_modules/,
  use: [
    {
      loader: "babel-loader",
      options: {
        // plugins: [
        //   "@babel/plugin-transform-arrow-functions",
        //   "@babel/plugin-transform-block-scoping",
        // ],
        presets: ["@babel/preset-env"],
      },
    },
  ],
},

webpack-dev-server

我们目前要打开编写好的网页每次都需要运行 npm run build ,否则无法通过修改代码同步修改 ./dist 中打包的代码,这样流程太过繁琐冗余,需要一种合理的解决方案来实现自动重新编译。

解决方案1—— watch 开发模式 + live server 插件

  1. 使用 watch:配置 package.json 中 build 为 "build": "webpack --watch"
  2. 使用 webpack 配置文件:修改 webpack.config.json 配置文件,添加 watch: true

缺点:

  • 所有源代码都会重新编译
  • 每次编译成功都需要进行文件重新读写到 ./dist
  • live server 只是 vscode 生态下的
  • 不能实现网页的局部刷新

解决方案2:webpack-dev-server

安装 webpack-dev-server

 npm i webpack-dev-server -D

基本使用

修改 package.json 增加短命令 "serve": "webpack serve"

"scripts": {
  "test": "echo \"Error: no test specified\" && exit 1",
  "build": "webpack",
  "serve": "webpack serve  --config webpack.config.js"
}

开启 serve 静态服务,默认端口为 8080

npm run serve

优点:

  • 脱离 vscode live server 插件,生态适用
  • 可以实现局部刷新
  • 打包全部在内存中进行,不需要进行文件读写

webpack-middleware

webpack-dev-middleware 是一个封装器( wrapper ),它可以把 webpack 处理过的文件发送到一个 server。webpack-dev-server 在内部使用了它,然而它也可以作为一个单独的 package 来使用,以便根据需求进行更多自定义设置。(webpack-dev-server 使用较多)

安装 core-js、regenerator-runtime 、 express 、 webpack-dev-middleware

npm i core-js regenerator-runtime express webpack-dev-middleware

Server.js 模拟服务端,使用 webpack-middleware

// 模拟服务端
const express = require("express");
const webpackDevMiddleware = require("webpack-dev-middleware");
const webpack = require("webpack");

// 使用 express 开启服务
const app = express();

// 获取配置文件
const config = require("./webpack.config.js");

// compiler 控制打包流程
const compiler = webpack(config);

// 将结果交给 server
app.use(webpackDevMiddleware(compiler));

// 开启端口上的服务监听
app.listen(3000, () => {
  console.log("服务运行在端口 3000 上");
});

// 开启服务

node ./Server.js

模块热替换 HMR

模块热替换(hot module replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允许在运行时更新所有类型的模块,而无需完全刷新。

开启HMR

配置:webpack.config.js

devServer: {
  hot: true,
},

为模块开启热更新, index.js ,整个方法也提供了回调函数,在发生更新是运行

import "./title.js";

if (module.hot) {
  module.hot.accept(["./title.js"], () => {
    console.log("title.js 模块更新了");
  });
}

React 组件支持 HMR

React 配置HMR 还需要额外的配置

配置 webpack 使支持 React

安装 @babel/core 、 @babel/preset-react

npm i @babel/preset-react -D
npm i @babel/core -D

在 webpack.config.json 添加 jsx 解析规则

// jsx
{
  test: /\.jsx?$/, // 以该规则解析 js 和 jsx
  use:['babel-loader']
}

在 babel.config.js 配置 babel

module.exports = {
  presets: [
    ["@babel/preset-env"],
    ["@babel/preset-react"],
  ],
};

配置 React HMR

安装 react-refresh-webpack-plugin 和 react-refresh (前者依赖它,配合使用)

npm install -D @pmmmwh/react-refresh-webpack-plugin react-refresh

配置 package.json

plugins: [
  new reactRefreshWebpackPlugin()
]

配置 babel.config

module.exports = {
  presets: [
    ["@babel/preset-env"],
    ["@babel/preset-react"],
  ],
  plugins: [["react-refresh/babel"]],
};

webpack 的几个 path

output 中的 path

webpack.config.js

const path = require("path");
module.exports = {
  entry: "./src/index.js",
  output: {
    filename: "main.js",
    // path :本地、产出---打包内容输出到本地的路径,使用 server 更多关注的是下面的 publicPath
    path: path.resolve(__dirname, "dist"), 
    // publicPath : 告知静态资源 index.html 内部的引用路径
    // 官网解释指定在浏览器中所引用的此输出目录对应的公开URL
    // webpack-dev-server 也会默认从 publicPath 为基准
    // 使用它来决定在哪个目录下启用服务,来访问 webpack 输出的文件
    // 值为 域名 + publicPath + filename
    // 默认为空串,浏览器会在还没补 '/',如果不想其补'/',可以写为'/'
    // 但这样如果还想打包 build 到本地 ./dist ,会找不到
    // 如果开启本地服务对其进行访问,建议使用 '/'
    // 强烈建议和 devServer 中的 publicPath 设置为一样的
    publicPath: '/', 
  }
};

devServer 中的 path

webpack.config.js 注意,webpack5 已移除以下属性,可参考 static

const path = require("path");
module.exports = {
  devServer: {
    // 指定本地服务所在的目录,即在哪开启服务,服务资源存在哪个目录(URL) static.publicPath
    publicPath: '/',
    // 打包之后的资源可能存在引入了一个没有被打包的资源,可以使用改属性指定,推荐使用绝对路径 static.directory
    contentBase: path.resolve(__dirname, 'public')
    // 实现未打包资源修改时实时刷新操作  static.watch
    watchContentBase: true
  },
}

devServer 常用配置

几个常用配置

const path = require("path");
module.exports = {
  devServer: {
    // webpack5 已改为 hot: 'only'
    // 遇到语法错误时值刷新错误的地方, 如果只是 hot 会全部刷新
    hotOnly: true, 
    // 运行服务的端口
    port: 4000,
    // 每次更新后自动重新打开浏览器,不建议打开
    open: false, 
    // 开启服务端,现已默认开启
    compress: true,
    // 当使用HTML5的 History API 时,index.html 页面可能会被用来代替任何 404 响应
    // 启用 devServer 的 historyApiFallback设置为 true 即可实现
    historyApiFallback
  },
}

proxy 设置

进行开发时,前后端可能不在一个端口上,或者需要请求其他地方的数据,那么就会存在浏览器跨域问题,就需要使用 proxy 进行代理

module.exports = {
  //...
  devServer: {
    proxy: {
      // /api 为标识符可以自定义,如果代码中出现 /api 字样就表明我们需要去转发请求
      // 不问自己要而是问别人要数据
      '/api': { 
        // 这里的 target 就是问谁要
        // 现在对 /api/users (只需要书写http://localhost:4000/api/users)的请求
        // 将请求代理到 https://api.github.com/users
        target: 'http://https://api.github.com', 
        // 后端不一定按我们定义的标识符去书写接口, pathRewrite 表示我们要把接口重写成什么
        // 这里假设后端接口就在 https://api.github.com
        // 则请求 users 只需请求 https://api.github.com/users
        pathRewrite: {"^/api" : ""}, 
        // 默认情况下,代理时会保留主机头的来源,可以将 changeOrigin 设置为 true 以覆盖此行为
        // 此处如果使用,那么请求的 HOST 可以看到(服务器才可以)被改成 https://api.github.com 
        changeOrigin: true,
      },
    },
  },
};

resolve 模块解析

配置模块如何被解析

resolve: {
  // 模块中怎么去找,按顺序
  modules: ['node_modules', "lg"],
  // 解析目录时要使用的文件名,只写到文件夹怎么解析
  mainFiles: ['index'],
  // 没有后缀怎么解析
  // 尝试按顺序解析这些后缀名
  // 如果有多个文件有相同的名字,但后缀名不同
  // webpack 会解析列在数组首位的后缀的文件 并跳过其余的后缀
  extensions: [".js", ".json", ".ts", ".jsx", ".vue"]
  // 使用别名
  alias: {
    "@": path.resolve(__dirname, "src"),
  },
},

mode

提供 mode 配置选项,告知 webpack 使用相应模式的内置优化。

module.exports = {
  mode: 'development',
};

默认值为 production

选项描述
development会将 DefinePluginprocess.env.NODE_ENV 的值设置为 development. 为模块和 chunk 启用有效的名。(源码阅读友好)
production会将 DefinePluginprocess.env.NODE_ENV 的值设置为 production。为模块和 chunk 启用确定性的混淆名称,FlagDependencyUsagePluginFlagIncludedChunksPluginModuleConcatenationPluginNoEmitOnErrorsPluginTerserPlugin 。(名称替换、删除注释、换行)
none不使用任何默认优化选项

devtool

source-map

source-map 是一种映射技术,可以根据转换的代码返还成为转化的源代码,这样调试的时候定位到源码中的信息

几种常见的 devtool 配置

适用开发环境:

  • eval :该模式会把每个 module 封装到 eval 里包裹起来执行,并且会在末尾追加注释 //@ sourceURL

    此选项会非常快地构建。主要缺点是,由于会映射到转换后的代码,而不是映射到原始代码(没有从 loader 中获取 source map),所以不能正确的显示行数

  • eval-source-map每个模块使用 eval() 执行,并且 source map 转换为 DataUrl 后添加到 eval() 中。初始化 source map 时比较慢,但是会在重新构建时提供比较快的速度,并且生成实际的文件行数能够正确映射,因为会映射到原始代码中。它会生成用于开发环境的最佳品质的 source map。

  • cheap-eval-source-mapeval-cheap-source-map - 类似 eval-source-map每个模块使用 eval() 执行。这是 " cheap (低开销)" 的 source map ,因为它没有生成列映射 ( column mapping ) ,只是映射行数。它会忽略源自 loader 的 source map,并且仅显示转译后的代码,就像 eval devtool。

  • cheap-module-eval-source-map :类似 eval-cheap-source-map,并且,在这种情况下,源自 loader 的 source map 会得到更好的处理结果。然而**,loader source map 会被简化为每行一个映射** ( mapping )

适用生产环境:

  • none : (省略 devtool 选项)-不触发 source map , 非常推荐
  • source-map生成 index.js.map 文件,,此文件记录了 source map 行列信息如何映射源代码的信息。它为 bundle 添加了一个引用注释,以便开发工具知道在哪里可以找到它,但是应该将服务器配置为不允许普通用户访问 source map 文件
  • hidden-source-mapsource-map 相同,但不会为 bundle 添加引用注释。如果你只想 source map 映射那些源自错误报告的错误堆栈跟踪信息,但不想为浏览器开发工具暴露你的 source map,这个选项会很有用。
  • nosources-source-map : 创建的 source map 不包含 sourcesContent(源代码内容)。它可以用来映射客户端上的堆栈跟踪,而无须暴露所有的源代码。你可以将 source map 文件部署到 web 服务器

tips

验证 devtool 名称时,我们期望使用某种模式, 但注意不要混淆 devtool 字符串的顺序, 模式是: [inline-|hidden-|eval-][nosources-][cheap-[module-]]source-map.

  • eval-: 为每个模块生成 source map 并通过 eval 附加它。建议用于开发,因为改进了重新生成性能。
  • inline- : 将 source map 内联到原始文件中,而不是创建单独的文件。
  • hidden- : 没有添加 source map 的引用。source map 没有部署,但仍然应该生成,例如用于错误报告的目的。
  • nosources- : source map 中不包含源代码。当需要引用原始文件时(需要进一步的配置选项),这可能很有用。

打包环境拆分与合并

修改 package.json 达到传递不同参数调用不同配置的目的

{
  "scripts": {
	"test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack",
    "serve": "webpack serve",
    "build2": "webpack  --config ./config/webpack.common.js --env production",
    "serve2": "webpack serve --config ./config/webpack.common.js --env development",
  }
}

建立三个分离的配置文件和一个 path 路径文件:

  • ./config/path.js

  • ./config/webpack.common.js

  • ./config/webpack.dev.js

  • ./config/webpack.prod.js

path.js 需匹配到的绝对路径都放在这个文件导出,使用时如 resolveApp('./src')

const path = require("path");

// 从进程的工作目录获取当前目录
const appDir = process.cwd();

const resolveApp = (relativePath) => {
  return path.resolve(appDir, relativePath);
};

module.exports = resolveApp;

./config/webpack.common.js

const {merge} = require("webpack-merge");
const prodConfig = require("webpack.prod");
const devConfig = require("webpack.dev");

module.exports = (env) => {
  // commonConfig
  const commonConfig = {
    // entry
    // output
    // resolve
    // module
    // plugin 视情况而定 HtmlWebpackPlugin 、 DefinePlugin
  };
    
  // 视环境合并config
  const isProduction = env.production;
  const config = isPtoduction ? prodConfig : devConfig;                    
  return merge(commonConfig, config)
};

./config/webpack.prod.js / ./config/webpack.dev.js 略

module.exports = (env) => {
  return {
    // mode: "production"
    // plugin 视情况而定 CleanWebpackPlugin 、 CopyWebpackPlugin
  };
};

建立三个分离的配置文件和一个 path 路径文件:

  • ./config/path.js

  • ./config/webpack.common.js

  • ./config/webpack.dev.js

  • ./config/webpack.prod.js

path.js 需匹配到的绝对路径都放在这个文件导出,使用时如 resolveApp('./src')

const path = require("path");

// 从进程的工作目录获取当前目录
const appDir = process.cwd();

const resolveApp = (relativePath) => {
  return path.resolve(appDir, relativePath);
};

module.exports = resolveApp;

./config/webpack.common.js

const {merge} = require("webpack-merge");
const prodConfig = require("webpack.prod");
const devConfig = require("webpack.dev");

module.exports = (env) => {
  // commonConfig
  const commonConfig = {
    // entry
    // output
    // resolve
    // module
    // plugin 视情况而定 HtmlWebpackPlugin 、 DefinePlugin
  };
    
  // 视环境合并config
  const isProduction = env.production;
  const config = isPtoduction ? prodConfig : devConfig;                    
  return merge(commonConfig, config)
};

./config/webpack.prod.js / ./config/webpack.dev.js 略

module.exports = (env) => {
  return {
    // mode: "production"
    // plugin 视情况而定 CleanWebpackPlugin 、 CopyWebpackPlugin
  };
};
  JavaScript知识库 最新文章
ES6的相关知识点
react 函数式组件 & react其他一些总结
Vue基础超详细
前端JS也可以连点成线(Vue中运用 AntVG6)
Vue事件处理的基本使用
Vue后台项目的记录 (一)
前后端分离vue跨域,devServer配置proxy代理
TypeScript
初识vuex
vue项目安装包指令收集
上一篇文章      下一篇文章      查看所有文章
加:2022-01-14 01:52:39  更:2022-01-14 01:54:23 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 12:33:07-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码