本文基于:峰华前端工程师--30分钟掌握Webpack

为什么使用 Webpack

在我们进行传统网页开发中,会在 index.html 中引入大量的 jscss 文件,不仅可能会导致命名冲突,还会使页面体积变大,因为如果引用了第三方库,需要加载所有的代码。而在 node.js 出现后,javascript 项目支持通过 require 支持模块化开发了,并且支出 npm 方便地管理依赖。

借着 node.js 和浏览器js 的一致性,前端项目开始在 node.js 下开发,完成之后把代码构建成浏览器支持的形式。对于 reactvue 这种组件化的开发方式,因为有很多分散的文件,那么久特别需要这样的构建操作。

Webpack 就是进行这一步构建操作的,把 node.js 模块化的代码转化为浏览器可执行的代码。它提供了 importexport ES6模块化语法的支持,然后通过分析代码中 import 导入的依赖,把需要的代码加载进来。在 Webpack 中,任何文件都可以通过 import 导入,只要有对应的 loader 就可以了。在打包过程中,还可以通过插件来干预打包过程,例如剔除不必要的代码,形成体积更小的项目。

创建项目

  • 打开命令行工具,我们在这里创建一个名为 blog 的博客项目:

    mkdir blog
    cd blog
    yarn init -y
    (或者npm init)
  • 添加 webpack 依赖:

    yarn add webpack webpack-cli --dev
  • 使用 VSCode 打开项目:

    code .

初出茅庐

  • blog 项目下新建 src 文件下,创建 index.js

    console.log("Hello World");

    我们先只做一个简单的输出.

  • blog 项目下新建 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>
    <h1>Hello World</h1>
    <script src="./dist/index.js"></script>
    </body>
    </html>
  • 使用 LiveServer 查看刚刚所编写的 html页面:

    可以看到浏览器成功显示了 "Hello World",并且控制台也能够成功输出.

  • 尝试使用 webpack 打包

    打开控制台,输入 npx webpack

npx 能够直接运行 node_modules 下面安装的库的自带的命令行,而不用写 node_modules 下一串的绝对路径。

打包完成后可以看到项目里面生成了一个 dist 目录,里面有一个 main.js 文件,其内部的内容和我们刚刚所编写的 index.js 的文件一模一样,这是因为我们并没有使用任何 import 来导入其他的依赖。

使用 import 导入依赖

  • src 下新建一个 data.js 文件:

    export function getBlogPosts() {
    return ["博客1", "博客2", "博客3"];
    }
  • index.js 中导入 data.js 中的函数并调用:

    import { getBlogPosts } from "./data";
    
    console.log(getBlogPosts());
  • 重新使用 webpack 打包以下,查看结果:

    npx webpack

    现在进入 /dist/main.js 中看一下,代码被简化成了直接输出刚才我们所编写的数组的语句,说明 webpack 自动判断了我们所编写代码的逻辑,并通过 import 语句得到了我们所引入的代码,分析后生成新的 js 文件.

  • 在网页中查看下结果:

    成功地输出了数组.

Webpack 配置文件

webpack 的配置文件可以说是 webpack 最核心的部分了,我们可以在配置文件中修改入口和出口文件、通过 loader 加载不同类型的文件和使用 plugins 对代码做其他的操作。

尝试修改打包后生成文件的名称

  • 在项目中新建 webpack.config.js 文件:

    const path = require("path");
    
    module.export = {
    mode: "development",
    // 设置为开发模式,方便调试
    entry: "./src/index.js",
    output: {
    filename: "dist.js",
    path: path.resolve(__dirname, "dist"),
    // 设置文件名和目录
    }
    }
  • 执行 npx webpack 命令打包

    可以看到 dist 文件夹下多了个 dist.js 文件.

使用模块化语法

  • 修改 /index.htmlscript 标签:

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

    main.js 修改成为我们刚刚使用 webpack 打包生成的 dist.js

  • 修改 /src/index.js 文件,将之前编写的数组变成 ul 元素插入页面中:

    const blogs = getBlogPosts();
    
    const ul = document.createElement("ul");
    blogs.forEach(blog => {
    const li = document.createElement("li");
    li.innerText = blog;
    ul.appendChild(li);
    }) document.body.appendChild(ul);
  • npx webpack

    列表成功插入到了页面.

引入 css

  • src 下新建 style.css 文件:

    h1 {
    color: blueviolet;
    }

    这里只是简单地改变 h1 标签的颜色.

  • /src/index.js 中引入 css 文件:

    import "./style.css";
  • 安装 loader

    打开控制台,输入:

    yarn add --dev style-loader css-loader
  • webpack.config.js 中配置 loader

    module.exports = {
    mode: "development",
    output: {...},
    ... module: {
    rules: [{
    test: /\.css$/i,
    use: ["style-loader", "css-loader"],
    }]
    }
    }

    module -> rules -> test 内是一个正则表达式,表示以 .css 结尾的文件.

    use 属性下是所使用的 loader

  • 再次使用 npx webpack 打包:

    可以看到,刚才写的样式生效了.

加载图片

  • webpack 原生支持图片等静态文件,但是需要在 webpack.config.js 中编写配置:

    module.exports = {
    ...
    module: {
    rules: [
    ...
    {
    test: /\.(png|svg|jpg|jpeg|gif)$/i,
    type: "assets/resource",
    }]
    }
    }
  • src 下载新建 assets/ 文件夹,放入一张图片:

  • index.js 中引入图片:

    import AbcImage from "./assets/abc.png"
    
    ...
    
    const image = document.createElement("img");
    image.src = AbcImage; document.body.prepend(image);
  • npx webpack

自动生成 HTML

上述的例子中,我们只是使用 webpack 来打包 jscss 文件,并手动的导入编写好的 html 中,使用下面的插件,就可以自动为我们生成 HTML 文件。

  • 安装插件:

    yarn add html-webpack-plugin --dev
  • 使用插件:

    const HtmlWebpackPlugin = require("html-webpack-plugin");
    ... plugins: [new HtmlWebpackPlugin({
    title: "博客列表",
    // 这里可以自定义网页的标题
    })],
  • npx webpack

    可以看到生成了和刚才相同的页面

使用 webpack 打包出来的网页没有显示 <h1>Hello World</h1> 的原因是 这个标签是我们自己写的

  • 定义打包好 html 文件的网页标题

    我们使用 html-webpack-plugins 打包生成的文件名默认是 Webpack App,其实网页标题是可以在插件内传递参数来更改的:

    plugins: [new HtmlWebpackPlugin({
    title: "博客列表",
    })],

Babel

有时我们的代码可能需要运行在更低版本的浏览器上,这些浏览器可能并不支持我们所写的更高级的代码,这时就需要用到 babel 转译工具来使我们的代码变成浏览器能够识别的代码。

  • 安装 babel-loader 相关依赖:

    yarn add --dev babel-loader @babel/core @babel/preset-env
  • webpack.config.js 中添加配置:

    rules: [
    ...
    {
    test: /\.js$/, // 识别js为结尾的文件
    exclude: /node_modules/, //不解释node_modules/下的文件
    use: {
    loader: "babel-loader",
    options: {
    presets: ["@babel/preset-env"]
    }
    }
    }]

    这里可以在 module.exports 下配置 devtool="inline-source-map" 方便查看打包后的源码

  • 使用 npx webpack 重新打包下,进入 dist/dist.js 查看相关代码:

    /* 打包前的 */
    blogs.forEach(blog => {
    const li = document.createElement("li");
    li.innerText = blog;
    ul.appendChild(li);
    })
    blogs.forEach(function (blog) {
    var li = document.createElement("li");
    li.innerText = blog;
    ul.appendChild(li);
    });

    可以看到 箭头函数已经被转换成了 .forEach 的形式,增强了对浏览器的兼容性。

使用 Terser 插件压缩打包后的代码

  • 安装插件:

    yarn add --dev terser-webpack-plugin
  • 配置:

    // webpack.config.js
    const TerserPlugin = require("terser-webpack-plugin"); module.exports = {
    ...
    optimization: {
    minimize: true,
    minimizer: [new TerserPlugin()],
    },
    }
  • 打包: npx webpack

    可以看到我们打包生成的 js 文件都被紧密地写在了一起,右键属性查看文件大小也要比之前的小一些。

使用 DevServer 插件自动打包

  • 安装:

    yarn add -dev webpack-dev-server
  • 配置:

    module.exports = {
    ...
    devServer: {
    static: "./dist",
    },
    }

    为了我们以后方便运行开发服务器,还需要在 package.json 里添加一个 script

    {
    ...
    "scripts": {
    "start": "webpack serve --open"
    },
    }
  • 启动服务器:

    yarn start
    // 或
    npm run start
  • 尝试一下 "热更新?"

    index.js 下添加如下代码:

    const header1 = document.createElement("h1");
    header1.innerText = "Hello";
    document.body.appendChild(header1);
  • 保存,查看网页

    这里不在使用 VsCodeLive Server 插件了,而是在浏览器地址栏输入命令行中输出的地址:

    成功!

    那么 webpack 是如何实现热更新的呢?其实是在我们每次保存时,插件自动生成新的 dist.js 并把之前的 dist.js 写入缓存,这或多或少会增加我们电脑的开销。但 webpack 贴心的为我们想到了这一点。

  • 每次打包生成新的 /dist.js

    配置 webpack.config.js

    output: {
    filename: "[name].[contenthash].js",
    // name 默认为 main
    path: path.resolve(__dirname, "dist"),
    },

    更改下 index.js 代码,运行 npx webpack

    可以看到生成了文件后缀名不同的文件,这样可以避免由于浏览器缓存机制而导致更新不及时的问题。

配置目录别名:

和之前写的 https://www.cnblogs.com/hhsk/p/16460701.html 大同小异

  • 配置:
    // webpack.config.js
    module.exports = {
    ...
    resolve: {
    alias: {
    assets: path.resolve(__dirname, "src/assets")
    }
    }
    }

30分钟掌握 Webpack的更多相关文章

  1. 30分钟学webpack实战

    阅读目录 一:什么是webpack? 他有什么优点? 二:如何安装和配置 三:理解webpack加载器 四:理解less-loader加载器的使用 五:理解babel-loader加载器的含义 六:了 ...

  2. 30分钟手把手教你学webpack实战

    30分钟手把手教你学webpack实战 阅读目录 一:什么是webpack? 他有什么优点? 二:如何安装和配置 三:理解webpack加载器 四:理解less-loader加载器的使用 五:理解ba ...

  3. 每天记录一点:NetCore获得配置文件 appsettings.json vue-router页面传值及接收值 详解webpack + vue + node 打造单页面(入门篇) 30分钟手把手教你学webpack实战 vue.js+webpack模块管理及组件开发

    每天记录一点:NetCore获得配置文件 appsettings.json   用NetCore做项目如果用EF  ORM在网上有很多的配置连接字符串,读取以及使用方法 由于很多朋友用的其他ORM如S ...

  4. 30分钟掌握ES6/ES2015核心内容(下)

    在 30分钟掌握ES6/ES2015核心内容(上)我们讲解了es6最常用的一些语法:let, const, class, extends, super, arrow functions, templa ...

  5. 【微信小程序项目实践总结】30分钟从陌生到熟悉 web app 、native app、hybrid app比较 30分钟ES6从陌生到熟悉 【原创】浅谈内存泄露 HTML5 五子棋 - JS/Canvas 游戏 meta 详解,html5 meta 标签日常设置 C#中回滚TransactionScope的使用方法和原理

    [微信小程序项目实践总结]30分钟从陌生到熟悉 前言 我们之前对小程序做了基本学习: 1. 微信小程序开发07-列表页面怎么做 2. 微信小程序开发06-一个业务页面的完成 3. 微信小程序开发05- ...

  6. 30分钟学会XAML

    1.狂妄的WPF 相对传统的Windows图形编程,需要做很多复杂的工作,引用许多不同的API.例如:WinForm(带控件表单).GDI+(2D图形).DirectX API(3D图形)以及流媒体和 ...

  7. Shell脚本编程30分钟入门

    Shell脚本编程30分钟入门 转载地址: Shell脚本编程30分钟入门 什么是Shell脚本 示例 看个例子吧: #!/bin/sh cd ~ mkdir shell_tut cd shell_t ...

  8. JS组件系列——又一款MVVM组件:Vue(一:30分钟搞定前端增删改查)

    前言:关于Vue框架,好几个月之前就听说过,了解一项新技术之后,总是处于观望状态,一直在犹豫要不要系统学习下.正好最近有点空,就去官网了解了下,看上去还不错的一个组件,就抽空研究了下.最近园子里vue ...

  9. 2016windows(10) wamp 最简单30分钟thrift入门使用讲解,实现php作为服务器和客户端的hello world

    2016最简单windows(10) wamp 30分钟thrift入门使用讲解,实现php作为服务器和客户端的hello world thrift是什么 最简单解释 thrift是用来帮助各个编程语 ...

随机推荐

  1. 市面上的工业ERP系统如何区别?存在什么样的不同?

    工业发展当中所要涉及到的管理是繁琐而复杂的,在ERP系统的拓展开发中,市面上出现了很多的工业ERP系统来让企业选择.这是近年来非常受欢迎的一种管理手段,依靠计算机系统的强大功能,来实现数据化的管理,企 ...

  2. 年中盘点 | 2022年,PaaS 再升级

    作者丨刘世民(Sammy Liu)全文共7741个字,预计阅读需要15分钟 过去十五年,是云计算从无到有突飞猛进的十五年.PaaS作为云计算的重要组成部分,在伴随着云计算高速发展的同时,在云计算产业链 ...

  3. NOI / 2.1基本算法之枚举 1749:数字方格

    描述: 如上图,有3个方格,每个方格里面都有一个整数a1,a2,a3.已知0 <= a1, a2, a3 <= n,而且a1 + a2是2的倍数,a2 + a3是3的倍数, a1 + a2 ...

  4. [极客大挑战 2019]BabySQL-1|SQL注入

    1.打开题目之后,查看源代码信息,发现check.php文件,结果如下: 2.那就只能尝试登录,经测试当输入or.by.select.from.and.where等关键字时会被过滤且会被过滤为空(过滤 ...

  5. Windows环境中Hadoop配置

    我们之前已经在Windows中安装好了Hadoop,并且配置了环境变量.如果要在本地上运行的,还需要这两个文件,可以去找一下,放到Hadoop的bin目录下面.这样我们写好的mr程序就可以直接在Win ...

  6. Regular采样类定义和测试

    这个算法是均匀采样算法,继承于Sampler类. 类声明: #pragma once #ifndef __REGULAR_HEADER__ #define __REGULAR_HEADER__ #in ...

  7. WPF主窗体调用 User32的SetWindowPos 设置窗体置顶会导致与其他窗体抢夺焦点的问题

    最近发现:自己开发的窗体应用,在二级弹窗或者提示框弹出的时候,交替点击窗体和窗体外(相当于窗体交替的获取焦点和失去焦点),都会导致其他的应用一闪一闪的. 经过排查,是由于该窗体由于部分因素考虑,用了  ...

  8. Luogu2915 [USACO08NOV]奶牛混合起来Mixed Up Cows (状压DP)

    枚举末位状态 #include <iostream> #include <cstdio> #include <cstring> #include <algor ...

  9. Redis入门到实战

    一.Redis基础 Redis所有的命令都可以去官方网站查看 1.基本命令 keys * 查找所有符合给定模式pattern(正则表达式)的 key .可以进行模糊匹配 del key1,key2,. ...

  10. 管理 MongoDB 用户和权限

    创建用户 创建用户的函数是:db.createUser(). 创建用户时,需要为该用户添加权限.可添加的权限以及说明: 权限 作用 read 允许用户读取指定数据库. readWrite 允许用户读写 ...