阅读 244

Webpack5不完全指南-基础篇

金石有声,不拷不鸣

引言

在webpack之类的构建工具诞生之前,前端项目构建一直处于"高耕火种"时代,项目代码压缩混淆、 js/css等依赖的合并都需要手动操作。webpack的出现解决了前端项目构建的很多痛点,可以说是前端工程化中必学必会的一环。

什么是Webpack?

Webpack  是前端项目的构建工具,它可以解析项目的依赖(js/css/图片资源等),对它们进行打包处理。

Webpack主要功能:

  • 代码转译

  • 模块合并

  • 混淆压缩

  • 代码分割

  • 代码刷新

  • 自动刷新

  • 自动部署

webpack环境搭建

webpack基于Node环境,Node请自行下载

Webpack安装

全局安装:  npm install webpack webpack-cli -g

局部安装(推荐):  npm install webpack webpack-cli -D

搭建Demo

  • 新建basic文件夹并用Vscode打开

  • 局部安装 webpack webpack-cli

    • npm install webpack webpack-cli -D

Webpack-cli

Webpack-cli之前是再webpack包中的,webpack 4.0以后作为单独的模块进行管理。

执行Webpack

Webpack 通过指令 webpack 来对项目进行打包,但是这个指令只在全局安装的Webpack有用。npm5.2 提供了 npx 指令,npx 可以在项目中直接执行模块的指令。

终端执行npx webpack

image.png

webpack执行了,但是依赖和配置有问题,打包的入口、出口文件等都需要配置。

新建默认入口文件

webpack默认入口文件为: 根目录/src/index.js

  • 新建 根目录/src/index.js

    // /src/index.js const init = () => {   console.log("webpack真好玩") } init() 复制代码

  • 执行 npx webpack,打包成功生成 /dist/main.js

    image.png

应用场景

在真实开发中会涉及多个模块依赖的场景

  • 新建 src/a.js

    // moduleA console.log("我是模块A"); module.exports = {   name: "moduleA" } 复制代码

  • src/index.js 导入 a.js  并重新构建

    const a = require("./a") console.log(a.name); const init = () => {   console.log("webpack真好玩") } init() 复制代码

  • 安装vscode插件 - run code ,并执行 main.js

    image.png

在浏览器端执行

前面的 requiremodule.exports属于 CommonJS模块化规范 ,浏览器默认不支持该语法。但是代码经过webpack打包后,会自动转换模块化规范。

  • 新建 index.html (src/index.html),引入 src/index.js

    <!DOCTYPE html> <html> <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>   <!-- 使用CommonJS模块化规范 -->   <script src="./index.js"></script> </body> </html> 复制代码

    image.png

  • 引入 dist/main.js

    <body>   <!-- 使用CommonJS模块化规范 -->   <!-- <script src="./src/index.js"></script> -->   <!-- 引入webpack打包后的js -->   <script src="./dist/main.js"></script> </body> 复制代码

    image.png

Webpack配置

webpack四大核心概念:

  • 入口(entry):程序入口的js

  • 出口(output):打包之后存放的位置

  • loader:对项目依赖、文件进行转换处理

  • plugin:可以处理loader做不了的工作

Webpack配置文件

Webpack配置文件名默认为 webpack.config.js,配置文件必须遵守 CommmonJS 模块化规范。

const path = require("path") // webpack配置文件必须遵循CommonJS规范 module.exports = {   // 项目打包入口文件   entry: "./src/index.js",   // 项目出口配置   output: {     // path.resolve("path")/path.join(_dirname,"path"):将相对路径解析为绝对路径     path: path.resolve("./dist/"),     // 打包后的文件名     filename: 'bundle.js'   },   // 打包模式(默认:production):production || development    mode: "development" } 复制代码

webpack指令参数

  • --config 文件名

    使用自定义配置文件执行打包指令:npx webpack --config webpack.custom.config.js

    可以根据开发 / 上线 不同环境使用不同的配置文件

  • 新增script指令

    {   "scripts": {      // 终端输入 npm run build,使用 webpack.custom.config.js进行打包     "build": "npx webpack --config webpack.custom.config.js"   } } 复制代码

    image.png

html插件

webpack每次编译打包不会将index.html打包进来,通过html插件可以打包html文件同时自动引入其他css/js等依赖

html插件作用
1、打包后自动复制一份目标html文件
2、html自动引入打包后的js(注意:不要手动引入js!!!)

  • 安装:npm i html-webpack-plugin -D

  • 在webpack配置文件中配置插件

    // webpack.config.js const HtmlPlugin = require("html-webpack-plugin") module.exports = {   mode: "production",   // 配置插件字段   plugins: [     // 新建一个HtmlPlugin实例     new HtmlPlugin(       {         // 打包输出文件名         filename: "index.html",         // 被复制的目标html         template: "./src/index.html"       }     )   ] } 复制代码

  • 修改index.html

    <body> <!-- 使用CommonJS模块化规范 --> <!-- <script src="./src/index.js"></script> --> <!--新增节点-->   <ul>     <li>1</li>     <li>1</li>     <li>1</li>     <li>1</li>     <li>1</li>     <li>1</li>     <li>1</li>     <li>1</li>     <li>1</li>   </ul>   <!--使用html-webpack-plugin无需引入js,它会自动帮你引入-->   <!--<script src="./src/index.js"></script>--> </body> 复制代码

  • 执行指令  npx webpack进行打包

    image.png

自动编译工具

每次修改代码后,都要执行npm run build重新编译,我们可以借助插件或工具让webpack进行自动编译

  • watch mode

  • webpack-dev-server(最推荐)

  • webpack-dev-middleware

watch mode

webpack 开启watch模式,会监视项目文件的变化,当发现有修改的代码时会自动编译打包,输出文件。

方式一:webpack-cli打包指令增加--wtach参数

1、package.json 新增 watch 脚本

"scripts": {   "build": "npx webpack --config webpack.custom.config.js",   "watch": "npx webpack --config webpack.config.js --watch" } 复制代码

2、终端执行 npm run watch,开始监听项目文件

方式二:webpack配置文件开启watch模式

// webpack.config.js module.exports = {   // 打包模式(默认:production):production || development    mode: "production",   // 开启watch模式   watch: true } 复制代码

webpack-dev-server

这个npm包可以在本地开启服务,在内存中生成打包的bundle.js.打包效率高在修改代码后重新构建并刷新页面。注意:使用webpack-dev-server 必须先安装webpack

  • 1、安装 webpack-dev-servernpm i webpack-dev-server -D

  • 2、 webpack-dev-server 指令:npx webpack-dev-server --port 3001

    • --port:指定服务端口号

    • --hot:开启热更新

    • --open:是否自动打开浏览器访问页面

  • 3、配置 serve 脚本 执行脚本

  "scripts": {     "serve": "npx webpack-dev-server --port 3001 --open",   } 复制代码

image.png

当然也可以通过webpack配置文件的 devServer 字段开启 webpack-dev-server 服务

  • 1、 配置 devServer 字段

 // webpack.config.js  module.exports = {   // 开启watch模式   // watch: false,   // 配置 webpack-dev-server   devServer: {     // 编译完成是否自动打开页面     open: true,     // 服务端口号     port: 3000,     // 是否启用压缩     compress: true,     // 是否启用热更新     hot: true,     // 服务的基准路径     contentBase: "./src"   } } 复制代码

  • 2、配置 dev 脚本 执行脚本

 "scripts": {     "build": "npx webpack --config webpack.custom.config.js",     "watch": "npx webpack --config webpack.config.js --watch",     "serve": "npx webpack-dev-server --port 3001 --open",     "dev": "npx webpack serve"   } 复制代码

webpack-dev-middleware

webpack-dev-middleware 使用node的中间件,它可以作为一个容器将webpack打包后的资源提供给服务器。webpack-dev-server 也是通过这个实现的

  • 安装 expresswebpack-dev-middleware
    npm i express webpack-dev-middleware -D

  • 根目录新建 server.js

    // 新建服务 并运行   // 导入express框架 const express = require("express") // 导入webpack const webpack = require("webpack") // 导入中间件 const webpackDevMiddleware = require("webpack-dev-middleware") // 导入webpack配置对象 const config = require("./webpack.config.js") // 新建服务 const app = express() const compiler = webpack(config) // app注册中间件 app.use(webpackDevMiddleware(compiler, { publicPath: "/" })) // 监听服务 app.listen(3001, function () {   console.log("3000端口服务运行"); }) 复制代码

  • 新增脚本 server, 并执行

     "scripts": {   "server": "node server.js" } 复制代码

处理css文件

webpack默认无法处理css文件,我们需要借助相关loader进行处理

image.png image.png

  • 安装 css-loading npm i css-loader style-loader -D

  • 配置文件中配置loader(webpack.config.js)

      // 配置各种loader module: {   rules: [     //  配置用来解析css相关loader      {       // loader匹配到的文件       test: /\.css$/i,       // webpack调用loader的顺序是从右到左       use: ['style-loader', 'css-loader']     }   ] }, 复制代码

  • 新建 src/css/index.css

    li {  line-height: 100px;  background-color: red; } 复制代码

  • 入口文件导入css
    html引入的资源文件 webpack不会打包,我们需要将css文件引入到 src/index/js

    // src/index.js // 在webpack的入口文件中引入css import style from './css/index.css' 复制代码

  • 执行 npm run serve

    image.png

处理less/scss文件

css预处理器的文件 webpack也可以打包处理,这里以 less 为例

  • 安装 loader
    npm i less-loader -D

  • 新建 src/less/index.less

    ul {   li:nth-child(1) {     background-color: pink;     color: green;   } } 复制代码

  • 在入口文件中导入less

    // 在webpack的入口文件中引入less import './less/index.less' 复制代码

  • 配置less-loader (webpack.config.js)

      // 配置各种loader module: {   rules: [     {       test: /\.css$/i,       // webpack调用loader的顺序是从右到左       use: ['style-loader', 'css-loader']     },     //  配置用来解析.less相关loader      {       test: /\.less$/i,       // webpack调用loader的顺序是从右到左       use: ['style-loader', 'css-loader', 'less-loader']     }   ] } 复制代码

  • 执行 npm run serve ,查看效果

处理图片字体文件

图片和字体文件也需要loader来处理

webpack4

file-loader:处理图片等文件
url-loader:处理图片等文件,可将图片转为base64格式
注意:url-loader 是对 file-loader 的包装,使用 url-loader 必须安装 file-loader

  • 安装
    npm i fild-loader url-loader -D

  • 配置相关loader (webpack.config.js)

    module: {   rules: [   //  配置用来解析图片等文件相关loader      {       test: /\.jpg|png|gif|bmp|ttf|eot|svg|woff|wpff2$/i,       // 图片大小大于16940自动转为base64格式       use: 'url-loader?limit=16940'       // 使用file-loader       // use: 'file-loader'     }] } 复制代码

webpack5

webpack5 通过内置的 Asset Modules 引入任何其他类型的文件
1、asset/resource 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现。
2、asset/inline 导出一个资源的 data URI。之前通过使用 url-loader 实现。
3、asset/source 导出资源的源代码。之前通过使用 raw-loader 实现。
4、asset 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader,并且配置资源体积限制实现。

  • 配置文件(webpack.config.js)

    module: {   rules: [     //  配置用来解析图片等文件相关loader      {       test: /\.jpg|png|gif|bmp|ttf|eot|svg|woff|wpff2$/i,       type: "asset",       //解析       parser: {         //转base64的条件         dataUrlCondition: {           // 大于100kb转为base64格式           maxSize: 100, // 25kb         }       },       generator: {         //输出路径         // name:使用原文件名           // hash:文件名增加hash字符         // ext:使用原文件拓展名         filename: 'img/[name].[hash:6][ext]',         //打包后对资源的引入,文件命名已经有/img了         publicPath: './'       }     }   ] }, 复制代码

配置babel

webpack可以通过babel打包解析高级语法,将它们转换成可兼容绝大多数浏览器的代码

  • 安装
    npm install babel-loader babel-core babel-preset-env

  • 配置 bable-loader (webpack.custom.config.js)

    // 配置各种loader module: {   rules: [     // 解析所有.js文件     {       test: /\.js$/,       // 排除node_modules等文件       exclude: /(node_modules|bower_components)/,       use: {         // 使用 babel-loader         loader: 'babel-loader',         options: {           // 使用 babel的预设           presets: ['@babel/preset-env']         }       }     }   ] } 复制代码

使用bebal处理generator

js一些最新语法或者处于草案阶段的语法,babel需要借助相应的插件进行处理。

// index.js ...... const zs = new Person({ name: "张三" }) console.log("zs", zs.name); const init = () => {   console.log("webpack真好玩123fsd") } init() // 使用generator function* fn() {  yield 1  yield 2  return 3 } let newFn = fn() console.log("next1:", newFn.next()) console.log("next2:", newFn.next()) 复制代码

打包后会报错

image.png

  • 安装 plugin-transform-runtime

    npm i @babel/plugin-transform-runtime -D // @babel/runtime 是 @babel/plugin-transform-runtime的核心依赖 npm install --save @babel/runtime   复制代码

  • 配合打包配置 babel-loader  (webpack.custom.config.js)

     module: {   rules: [     {       test: /\.js$/,       exclude: /(node_modules|bower_components)/,       use: {         loader: 'babel-loader',         options: {           presets: ['@babel/preset-env'],           // 注册babel插件           plugins: ["@babel/plugin-transform-runtime"]         }       }     }   ] }, 复制代码

  • npm run build 执行 webpack.custom.config.js

babel配置文件

babel作为一个工具,可能会有大量需要配置的地方,如果在webpack配置babel可能会造成webpack配置文件体量过于庞大、可读性差等问题。这时候可以通过babel的独立配置文件解决这个问题

.babelrc.json

在项目根目录新建 .babelrc.json ,将 babel-loader 的 options 字段移植到 .babelrc.json 中.

// .babelrc.json   {   "presets": [     "@babel/preset-env"   ],   "plugins": [     "@babel/plugin-transform-runtime"   ] } // webpack.custom.config.js         {         test: /\.js$/,         // 排除node_modules等文件         exclude: /(node_modules|bower_components)/,         use: {           // 使用 babel-loader           loader: 'babel-loader',           // 移植到 .babelrc.json中           // options: {           //   // 使用 babel的预设           //   presets: ['@babel/preset-env'],           //   plugins: ["@babel/plugin-transform-runtime"]           // }         }       } 复制代码

使用bebal处理实例的原型方法

某些实例的原型方法babel不会进行转换成低级代码,可能会出现兼容性问题。例如数组实例的map、includes等方法。

image.png

@babel/polyfill

他是 @babel/plugin-transform-runtime的补丁,只需要安装一下在使用实例原型方法的位置导入进行即可

  • 安装
    npm i @babel/polyfill -D

  • 导入

    // src/index.js // 导入polyfill import '@babel/polyfill' const arr = [1, 2, 3] console.log("arr是否包含 '1'", arr.includes(1)); console.log(arr.map(e => e + 2)); `` 复制代码

sourceMap

Sourcemap 本质上是一个信息文件,里面储存着代码转换前后的对应位置信息。它记录了转换压缩后的代码所对应的转换前的源代码位置。webpack会对源码进行压缩、编译、高版本代码到低版本代码的转换,会导致处理后代码阅读性很差,无法追踪bug错误,Sourcemap就是解决这一问题的利器。Sourcemap可以在生产环境使用但是极不推荐!!会造成源码泄露的风险

devtool

devtool是webpack配置项,用来控制使用sourceMap的方式
[inline-|hiddeb-|eval-][nosources-][cheap-[module-]]source-map

source-map

devtool:source-map 是最基本的用法
特点

  • 外部单独一个sourcemap文件

  • 可以提供错误代码准确位置,源代码的错误位置

示例

  • 手写一个bug

    const a = require("./a") import './css/index.css' import './less/index.less' import img from './img/avatar.jpg' console.log(a.name); class Person {   constructor(opt) {     this.name = opt.name   } } // 手动声明一个错误(在console.log()后加上()) const zs = new Person({ name: "张三" }); console.log("zs", zs.name)(); 复制代码

  • 配置 webpack.config.js

    const path = require("path") const HtmlPlugin = require("html-webpack-plugin") module.exports = {   entry: "./src/index.js",   output: {     path: path.resolve(__dirname, "./dist"),     filename: 'bundle.js'   },   mode: "production",   plugins: [     new HtmlPlugin(       {filename: "index.html",template: "./src/index.html"}     )   ],   module: {     rules: [       { test: /\.css$/i,use: ['style-loader', 'css-loader']},       { test: /\.less$/i, use: ['style-loader', 'css-loader', 'less-loader']},       {         test: /\.jpg|png|gif|bmp|ttf|eot|svg|woff|wpff2$/i,         type: "asset",         parser: {           dataUrlCondition: {             maxSize: 100, // 25kb           }         },         generator: {           filename: 'img/[name].[hash:6][ext]',           publicPath: './'         }       },       {         test: /\.js$/,         exclude: /(node_modules|bower_components)/,         use: {loader: 'babel-loader' }       }     ]   },   // 开启source-map模式    devtool: "source-map" } 复制代码

  • 执行 npx webpack 构建项目,dist目录下生成.map文件

    image.png image.png

    image.png

inline-source-map

特点

  • 内联sourcemap,构建速度快。只生成一个sourcemap

  • 可以提供错误代码准确位置,源代码的错误位置

示例

  • 修改 webpack.config.js,将 devtool 改为 "inline-source-map"

    devtool: "inline-source-map" 复制代码

  • 删除dist目录,执行 npx webpack 重新构建项目,没有 .map 文件所有sourcemap数据会以base64的形式内嵌到 bundle.js

    image.png

hidden-source-map

特点

  • 外部sourcemap文件

  • 可以提示错误代码错误原因,没有错误位置

  • 不能追踪源代码错误位置,只能提示构建后错误代码位置

eval-source-map

特点

  • 内联sourcemap,每一个文件都有对应的source-map 都在eval

  • 可以提供错误代码信息,源代码的错误位置

nosources-source-map

特点

  • 外部单独一个sourcemap文件

  • 可以提供错误代码信息,没有任何源代码的信息

cheap-source-map

特点

  • 外部单独一个sourcemap文件

  • 可以提供错误代码信息和源代码错误位置(只精确到行)

cheap-module-source-map

特点

  • 外部单独一个sourcemap文件

  • 可以提供错误代码信息和源代码错误位置

开发环境:

开发环境 要求速度快、调试友好 速度
eval > inline > cheap > ...
eval-cheap-source-map>eval-source-map
调试
source-map
cheap-module-source-map
cheap-source-map
建议
eval-source-map(MVVM框架一般用这个) / eval-cheap-module-source-map

生产环境

生产环境要考虑代码是否要隐藏、调试友好,不能使用内联,内联会让代码体积变大
nosources-source-map
hidden-source-map
建议
source-map / cheap-module-source-map

clean-webpack-plugin

webpack每次构建生成新的dist目录,默认不会清空dist下的文件,这对导致有些缓存文件一直存在,clean-webpack-plugin会在构建项目前清空dist

  • 安装
    npm i clean-webpack-plugin -D

  • 配置plugin

    // webpack.custom.config.js   const CleanWebpackPlugin = require("clean-webpack-plugin").CleanWebpackPlugin module.exports = {     plugins: [      new HtmlPlugin(       {         filename: "index.html",         template: "./src/index.html"       }     ),     // new插件实例     new CleanWebpackPlugin()    ], } 复制代码

copy-webpack-plugin

webpack默认打包src下的所有资源,目录外的资源可以通过 copy-webpack-plugin 打包进来

image.png

  • 安装
    npm i copy-webpack-plugin -D

  • 配置plugin

    // webpack.custom.config.js   {   plugins:[     new CopyWebpackPlugin({     patterns: [{       // 将项目的assets目录复制一份到dist/assets中       from: path.join(__dirname, "assets"),       to: 'assets'     }]   })   ] } 复制代码

BannerPlugin

这是webpack内部的一个插件,用来为打包js添加注释、版本等信息

  • webpack.custom.config.js

    // 导入webpack const Webpack = require("webpack") module.exports = {   plugins: [      new Webpack.BannerPlugin("这是一段版权信息")   ] }


作者:_光光
链接:https://juejin.cn/post/7017718501099962399


文章分类
后端
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐