关于前端:webpack系列从核心概念到上手配置

5次阅读

共计 7908 个字符,预计需要花费 20 分钟才能阅读完成。

前言

作为前端开发者,置信大家或多或少都接触过 webpack,现如今webpack 曾经浸透在了前端的各个方面,所以咱们有必要来理解并学习 webpackwebpack 是一种用于构建 JavaScript 应用程序的动态模块打包器,它可能以一种绝对统一且凋谢的解决形式,加载利用中的所有资源文件(图片、CSS、视频、字体文件等),并将其合并打包成浏览器兼容的 Web 资源文件。webpack 相比其它构建工具性能更加弱小,可扩展性也更强,它可能交融多种工程化工具,将开发阶段的利用代码编译、打包成适宜网络散发、客户端运行的利用产物。

外围概念

输入输出

entry

webpack 的构建入口,入口终点(entry point) 批示 webpack 应该应用哪个模块,来作为构建其外部 依赖图(dependency graph) 的开始。进入入口终点后,webpack 会找出有哪些模块和库是入口终点(间接和间接)依赖的。

// 单入口
module.exports = {entry: './src/main.js'}
​
// 多入口
module.exports = {
  entry: {
    a: './src/a.js',
    b: './src/b.js'
  }
}

output

output 属性通知 webpack 在哪里输入它所创立的 bundle,以及如何命名这些文件。次要输入文件的默认值是 ./dist/main.js,其余生成文件默认搁置在 ./dist 文件夹中。

// 单入口
module.exports = {
  entry: './src/main.js',
  output: {
    filename: 'bundle.js',   
    path: path.resolve(__dirname, 'dist'),
  }
}
// 多入口
module.exports = {
  entry: {
    a: './src/a.js',
    b: './src/b.js'
  },
  output: {filename: '[name].[hash:6].js', // 通过占位符确保文件名惟一,思考缓存问题,还能够为文件名加上 hash
    path: __dirname + '/dist',
    publicPath: '/',    // 生产环境个别是 CDN 地址,开发环境配置为 / 或不配置
  }
}

模块解决

loader

webpack 只能了解 JavaScript 和 JSON 文件,这是 webpack 开箱可用的自带能力。loader 让 webpack 可能去解决其余类型的文件,并将它们转换为无效 模块,以供应用程序应用,以及被增加到依赖图中。

比方:配置 webpack 为 css 文件利用css-loader

module.exports = {
  module: {
    rules: [{test: /.css$/, use: 'css-loader'}
    ]
  }
}

module.rules 容许你在 webpack 配置中指定多个 loader。这种形式是展现 loader 的一种扼要形式,并且有助于使代码变得简洁和易于保护。

plugin

插件 是 webpack 的 支柱 性能。Webpack 本身也是构建于你在 webpack 配置中用到的 雷同的插件零碎 之上!

插件目标在于解决 loader 无奈实现的 其余事。Webpack 提供很多开箱即用的 插件。

比方:为编译过程增加进度报告插件

const Webpack = require('webpack')
module.exports = {plugins: [new Webpack.ProgressPlugin()]
}

resolve

用于配置模块门路解析规定,可用于帮忙 Webpack 更准确、高效地找到指定模块

比方配置别名:

创立 importrequire 的别名,来确保模块引入变得更简略。例如,一些位于 src/ 文件夹下的罕用模块:

module.exports = {
  resolve: {
    alias: {node_modules: path.resolve(__dirname, './node_modules'),
      '@': path.resolve(__dirname, './src'),
      api: path.resolve(__dirname, './src/api'),
      components: path.join(__dirname, './src/components'),
    }
  }
}

module

这些选项决定了如何解决我的项目中的不同类型的模块。

比方咱们常见的 loader 就是在 module.rules 内配置的。

module.exports = {
  module: {
    rules: [{test: /.css$/, use: 'css-loader'}
    ]
  }
}

externals

用于申明内部资源,Webpack 会间接疏忽这部分资源,跳过这些资源的解析、打包操作

比方 避免 将某些 import 的包 (package) 打包 到 bundle 中,而是在运行时 (runtime) 再去从内部获取这些 扩大依赖(external dependencies)

比方:从 CDN 引入 Vue

<!-- index.html -->
<script src="https://cdn.bootcdn.net/ajax/libs/vue/2.6.3/vue.min.js"></script>
// webpack.config.js
module.exports = {
  externals: {vue: 'vue'}
}

后处理

optimization

用于管制如何优化产物包体积,内置 Dead Code Elimination、Scope Hoisting、代码混同、代码压缩等性能

从 webpack 4 开始,会依据你抉择的 mode 来执行不同的优化,不过所有的优化还是能够手动配置和重写。

module.exports = {
  //...
  optimization: {chunkIds: 'named',},
};

target

用于配置编译产物的指标运行环境,反对 web、node、electron 等值,不同值最终产物会有所差别

比方:target 设置为 node,webpack 将在 node 环境下进行编译

module.exports = {target: 'node'}

mode

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

string = 'production': 'none' | 'development' | 'production'
module.exports = {mode: 'development',};

或者从 cli--mode 参数进行传递

webpack --mode development

开发效率

watch

启用 Watch 模式。这意味着在初始构建之后,webpack 将持续监听任何已解析文件的更改。

module.exports = {watch: true}

⚠️留神:webpack-dev-serverwebpack-dev-middleware 默认是开启 watch 模式的

devtool

此选项管制是否生成,以及如何生成 source map。

string = 'eval' | false

抉择一种 source map 格调来加强调试过程。不同的值会显著影响到构建 (build) 和从新构建 (rebuild) 的速度。

devServer

用于配置与 HMR 强相干的开发服务器性能

通过 webpack-dev-server 的这些配置,可能以多种形式扭转其行为,这里比拟常见的配置有:porthostproxy

module.exports = {
  devServer: {
    static: {directory: path.join(__dirname, 'public'),
    },
    compress: true,
    port: 9000,
  }
}

cache

Webpack 5 之后,该项用于管制如何缓存编译过程信息与编译后果

缓存生成的 webpack 模块和 chunk,来改善构建速度。cache 会在 开发 模式被设置成 type: 'memory' 而且在 生产 模式 中被禁用。cache: truecache: {type: 'memory'} 配置作用统一。传入 false 会禁用缓存:

module.exports = {cache: false}

上手配置

理解完下面这些 webpack 外围概念,咱们能够尝试来手动配置好一个 Vue 开发环境

初始化我的项目

首先 npm init -y 初始化 package.json 文件

接着装置好咱们的webpackwebpack-cli

npm i webpack webpack-cli -D

⚠️留神:我这里的 webpack 是 5 版本的

"webpack": "^5.85.1",
"webpack-cli": "^4.7.2",

解决 Vue 代码

原生 Webpack 并不能解决这种内容格局的文件,为此咱们须要引入专用于 Vue SFC 的加载器:vue-loader

npm i vue-loader
// webpack.config.js

const Webpack = require('webpack')
const {VueLoaderPlugin}  = require('vue-loader')
module.exports = {
    entry: './src/main.js',
    output: {filename: 'bundle.[hash:6].js',
        path: __dirname + '/dist',
    },
    module: {
        rules:[{test: /.vue$/, use: 'vue-loader'}, 
        ]
    },
    plugins:[new Webpack.ProgressPlugin(),
        new VueLoaderPlugin(),],
}

提醒:vue-loader 库同时提供用于解决 SFC 代码转译的 Loader 组件,与用于解决上下文兼容性的 Plugin 组件,两者须要同时配置能力失常运行。

此时咱们的文件构造是这样的,大抵与 Vue 我的项目构造统一

尝试启动看一下:

// package.json
"dev": "webpack --mode development",
npm run dev

因为咱们的 vue 文件中有 css 内容,而 webpack 默认是不了解 css 内容的,所以导致报错了

解决 CSS 内容

这里须要装置 style-loadercss-loader 来进行解决。

批改 webpack 配置

// webpack.config.js
const Webpack = require('webpack')
const {VueLoaderPlugin}  = require('vue-loader')
module.exports = {
    entry: './src/main.js',
    output: {filename: 'bundle.[hash:6].js',
        path: __dirname + '/dist',
    },
    module: {
        rules:[{test: /.vue$/, use: 'vue-loader'},
            {
                test: /.css$/,
                use: ['style-loader', 'css-loader']
            }
        ]
    },
    plugins:[new Webpack.ProgressPlugin(),
        new VueLoaderPlugin(),],
}

此时再跑起来,发现没有报错了。

解决 JS 内容

咱们平时在开发中必定会用到 ES6 语法,这里咱们也须要配置对应的 loader 来进行解决

装置 babel-loader

npm i babel-loader @babel/preset-env @babel/core

配置

module.exports = {
  module: {
    rules: [
      {
        test: /.js$/,
        use: {
          loader: 'babel-loader',
          options: {presets: ['@babel/preset-env']
          }
        },
        exclude: /node_modules/
      }
    ]
  }
}

当然这里的 options 配置你也能够在 .babelrcbabel.config.js中独自配置。

解决图片资源

与 CSS 一样,webpack 也是默认不了解图片的,所以这里也须要配置 loader 进行解决。

webpack4

在 webpack4 中,咱们罕用的解决图片的 loader 有:file-loaderurl-loader

  • file-loader 将文件发送到输入目录
// webpack.config.js
module.exports = {
  // ...
  module: {
    rules: [{test: /.(png|jpg|gif|jpeg)$/,
      use: ['file-loader']
    }],
  },
};

通过 file-loader 解决后,原始图片会被重命名并复制到产物文件夹,同时在代码中插入图片 URL 地址

  • url-loader 将文件作为 data URI 内联到 bundle 中,它有两种体现,对于小于阈值 limit 的图像间接转化为 base64 编码;大于阈值的图像则调用 file-loader 进行加载
module.exports = {
  // ...
  module: {
    rules: [{test: /.(png|jpg|gif|jpeg)$/,
      use: [{
        loader: 'url-loader',
        options: {limit: 1024}
      }]
    }],
  },
};

通过 url-loader 解决后,小于 limit 参数即 1024B 的图片会被转译为 Base64 编码,对于超过 limit 值的图片则间接调用 file-loader 实现加载。

webpack5

file-loaderurl-loader并不局限于解决图片,它们还能够被用于加载任意类型的多媒体或文本文件,应用频率极高,简直曾经成为标配组件!所以 Webpack5 间接内置了这些能力,开箱即可应用。

用法上,本来须要装置、导入 Loader,Webpack5 之后只须要通过 module.rules.type 属性指定资源类型即可

比方:

module.exports = {
  // ...
  module: {
    rules: [{test: /.(png|jpg|gif|jpeg)$/,
      type: 'asset/resource'
    }],
  },
};

运行页面

配置了这么多内容,咱们却还不能看到页面的内容,心里必定不乐意,下面这几步操作其实就相当于翻译 Vue SFC 文件的内容,接下来咱们还须要让页面真正运行起来。

粗犷计划

有一种疾速验证咱们的打包配置是否正确:咱们只须要新建一个 html 文件,将打包产物引入进去,并创立好挂载节点就能够

<!-- public/index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    
</head>
<body>
    <div id="app"></div>
    <script src="../dist/bundle.42603d.js"></script>
</body>
</html>

咱们再把这个 html 文件在浏览器关上,就能看到咱们 vue 我的项目可能失常关上了。

这种计划有一种弊病就是:咱们打包进去的文件个别都会带有 hash,那就须要咱们每次在打包完后去html 文件批改引入的文件,这样是不是有点太吃力了,你们能忍吗?

优雅计划

下面那种计划在日常开发中显然是不能承受的,身为程序员能偷懒的中央必须得偷懒!

咱们能够利用上面两个工具让这个过程变得更加智能化、自动化。

html-webpack-plugin:主动生成 HTML 页面

HtmlWebpackPlugin 简化了 HTML 文件的创立,以便为你的 webpack 包提供服务。这对于那些文件名中蕴含哈希值,并且哈希值会随着每次编译而扭转的 webpack 包特地有用。

webpack-dev-server:让页面真正运行起来,并具备热更新能力。

webpack-dev-server 次要提供两种性能:

  • 联合 Webpack 工作流,提供基于 HTTP(S) 协定的动态资源服务;
  • 提供资源热更新能力,在放弃页面状态前提下自动更新页面代码,晋升开发效率。

装置

npm i html-webpack-plugin webpack-dev-server

批改配置

​
const Webpack = require('webpack')
const {VueLoaderPlugin}  = require('vue-loader')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
    entry: './src/main.js',
    output: {filename: 'bundle.[hash:6].js',
        path: __dirname + '/dist',
    },
    module: {
        rules:[{test: /.vue$/, use: 'vue-loader'},
            {
                test: /.css$/,
                use: ['style-loader', 'css-loader']
            },
            {
                test: /.js$/,
                use: {
                    loader: 'babel-loader',
                    options: {presets: ['@babel/preset-env']
                    }
                },
                exclude: /node_modules/
            },
            {test: /.(png|jpg|gif|jpeg)$/,
                type: 'asset/resource',
            }
        ]
    },
    plugins:[new Webpack.ProgressPlugin(),
        new VueLoaderPlugin(),
        new HtmlWebpackPlugin({
            template: './public/index.html',
            filename: 'index.html'
        })
    ],
    devServer: {
        hot: true,
        open: true
    }
}

批改启动脚本

"dev": "webpack serve --mode development"

运行

npm run dev

这时 webpack 就能主动帮咱们关上浏览器运行页面了

vue 文件内容如下:

<template>
    <div class="title">webpack + vue -- {{name}}</div>
    <img src="../asset/1.png" class="top_bg" />
</template>
​
<script setup>
import {ref} from 'vue'
const name = ref('前端南玖')
</script>
​
<style>
.title {
    font-size: 16px;
    font-weight: bold;
    color: salmon;
}
.top_bg {
    width: 100%;
    height: auto;
}
</style>

如果这篇文章有帮忙到你,❤️关注 + 点赞❤️激励一下作者,文章公众号首发,关注 前端南玖 第一工夫获取最新文章~

正文完
 0