likes
comments
collection
share

webpack5 的使用(一):起步

作者站长头像
站长
· 阅读数 90

前言

本系列将分多篇文章,逐一介绍 webpack5 的使用。 本系列比较新手向,适合从来没有使用过 webpack 或略知一二的人看,不适合希望深入 webpack 的人看。

起步

安装 webpack

webpack 依赖 node 环境,若没有安装 node,请先移步安装 node。

先创建一个空白文件夹 test,输入以下命令,初始化项目。

npm init

输入命令后,会提示你输入一些信息,直接 enter 下一步即可。

test 文件夹里将会自动创建一个 package.json 文件,该文件是这个项目的描述文件,用来存储项目的一些信息,如:项目名称、版本号、运行脚本等。

安装 webpack 和 webpack-cli(如果是 webpack4+,需要安装 webpack-cli)

npm install --save-dev webpack webpack-cli

在 package.json 文件中,可以看到新增了 devDependencies,并且里面含有 webpack 和 webpack-cli 及对应的版本号,说明已经成功安装好 webpack。

webpack5 的使用(一):起步

基本配置

在根目录下创建一个 src 目录,src 目录下创建一个 js 目录,里面创建一个 index.js 入口文件。

index.js 文件写上测试代码。

console.log('这是一个入口文件')

在根目录下创建一个 build 目录,创建一个 webpack.config.js 文件,里面写上如下代码。

const path = require('path')

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

entry 是用来写入口配置,output 是用来写出口配置。 path.resolve 方法用于生成绝对路径,这个方法有些难懂,可以理解为一个 cd 操作,先 cd 到第一个参数路径,再配合第二个参数生成绝对路径,可以看下此文章,当初,我也是看了这篇文章才恍然大悟。

这里的配置的用意就是:index.js 作为入口文件,构建后输出到 dist 目录下的 main.js 文件。

在 package.json 文件里的 script 添加一条 build 构建命令,如下:

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

运行命令 npm run build,我们可以发现根目录多了一个 dist 目录,里面有一个 main.js 文件。

webpack5 的使用(一):起步

因为现在没有 html 载体,js 将不能在浏览器运行的,下面将进行添加 html。

html-webpack-plugin

安装 html-webpack-plugin,该插件用于管理 html,利用好此插件可以开发单页面应用或多页面应用。

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

用法一:单页面

在 webpack.config.js,引入 html-webpack-plugin,并进行对应配置。

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

module.exports = {
    ...
    // 新增 plugins 属性
    plugins: [
        new HtmlWebpackPlugin({
          title: '首页'
        })
    ]
}

运行构建命令:npm run build。 我们可以发现,dist 目录自动生成了一个 title 为“首页”的 index.html,并且引入了 main.js。

webpack5 的使用(一):起步

用法二:多页面

但有时候我们的页面并不是一个页面,可能还有其他页面。 假设还需要开发其他两个页面:header.html 和 footer.html。

我们在 src 目录创建 html 目录,里面创建三个文件 index.html、header.html、footer.html,注意这里也需要创建 index.html 文件,我们不再需要 webpack 为我们自动生成页面,而是以这几个文件为模板生成。

修改 webpack 配置,如下:

module.exports = {
  entry: path.resolve(__dirname, '../src/js/index.js'),
  output: {
    filename: 'main.js',
    path: path.resolve(__dirname, '../dist')
  },
  plugins: [
    // new HtmlWebpackPlugin({
    //   title: '首页'
    // }),
    // 配置多个 HtmlWebpackPlugin,有多少个页面就配置多少个
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../src/html/index.html'),
      filename: 'index.html',
      chunks: ['main'] // 与入口文件对应的模块名(entry 配置),这里可以理解为引入 main.js
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../src/html/header.html'),
      filename: 'header.html',
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../src/html/footer.html'),
      filename: 'footer.html',
    }),
  ]
}

我们再 build 一下,可以发现 dist 目录下多了 header.html 和 footer.html。 但是如果 header.html 和 footer.html 也有自己的 js,应该怎么办? 我们还需要修改一下 entry 、output 和 HtmlWebpackPlugin 的配置。

先在 src/js 目录下创建 header.js 和 footer.js。 修改 webpack.config.js 里的 entry。

module.exports = {
    // entry: path.resolve(__dirname, '../src/js/index.js'),
    entry: {
        main: path.resolve(__dirname, '../src/js/index.js'),
        header: path.resolve(__dirname, '../src/js/header.js'),
        footer: path.resolve(__dirname, '../src/js/footer.js'),
    },
    output: {
        // filename: 'main.js',
        filename: '[name].[fullhash].js', // 不再指定文件名,用 [name] 来输出原文件名
        path: path.resolve(__dirname, '../dist')
    },
    plugins: [
    // new HtmlWebpackPlugin({
    //   title: '首页'
    // }),
    // 配置多个 HtmlWebpackPlugin,有多少个页面就配置多少个
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../src/html/index.html'),
      filename: 'index.html',
      chunks: ['main'] // 与入口文件对应的模块名(entry 配置),这里可以理解为引入 main.js
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../src/html/header.html'),
      filename: 'header.html',
      chunks: ['header'] // 添加 chunks
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../src/html/footer.html'),
      filename: 'footer.html',
      chunks: ['footer']
    }),
}

build 一下,可以发现 dist 目录包含了 main、header、footer 等相关 js。 你可能会发现 js 文件名会有一串码,这串码是哈希码,是上面 output 里面的“[fullhash]”起作用,为什么要有加这个代码? 我们都知道浏览器是有缓存的,每次打包部署一个项目,如果 js 文件名或引入 js 链接没有改变,浏览器将会使用上一次缓存下来的 js 文件,这显然不是我们想要的,因此每次打包时我们都给资源文件(js、css、图片等)添加一串不同的哈希码,防止浏览器使用缓存文件。

webpack5 的使用(一):起步

自动清理 dist 目录

细心的人可能会发现之前生成 main.js 依然还在,如果我们每次在构建时都要手动清理一下 dist 目录,会很麻烦。

webpack5 的使用(一):起步

新版本做法

现在 webpack 5.20.0+,已经自带清理功能,只要配置一下 output 的 clean 即可。

output: {
    // ...
    clean: true, // 在生成文件之前清空 output 目录
},

旧版本做法

旧版本,可以进行安装 clean-webpack-plugin 解决这个问题。

npm i -D clean-webpack-plugin

webpack.config.js

const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
    ...
    plugins: [
        ...
        new CleanWebpackPlugin(),
    ]
}

可以发现我们每次构建时,dist 目录都会被删除,然后再构建出新的 dist 目录和对应的内容。

注意:这个项目将采用旧版本做法。

webpack-dev-server

webpack-dev-server 是一个开发服务器,可以实现 HMR(模块热替换),所谓的 MHR 就是它把构建出来的文件保存到运行内存中,确保运行速度,每当你的开发代码发生改变时,立刻重新构建一遍到内存中,且通知浏览器更新页面内容。

利用 webpack-dev-server,我们可以大大提高开发效率。

安装 webpack-dev-server

npm i -D webpack-dev-server

webpack.config.js

module.exports = {
    ...
      devServer: {
        port: 3000,
        hot: true,
        contentBase: '../dist' // 如果出错,请将 contentBase 替换为 static
      },
}

如果上面的 contentBase 导致了报错,请改为 static。contentBase 是旧版本的写法,static 是新版本(大概是 webpack-dev-server 4+ )的写法。

package.json 添加脚本 dev

{
    ...
    "scripts": {
        "dev": "webpack server --config build/webpack.config.js --open",
        ...
    },
    ...
}

运行命令 npm run dev

我们可以发现浏览器自动打开并加载我们的页面了,如果不想要浏览器自动打开,删掉 dev 脚本命令里的 --open 即可。

当然,我们也可以自己输入 http://localhost:3000 (端口要看实际部署的) 进行加载页面。

注意:有些技术博客,在脚本命令那里可能是这样写的。

"scripts": {
    "dev": "webpack-dev-server --config build/webpack.config.js --open",
    ...
},

在 webpack-cli4(对应 webpack5,webpack-cli3 才是对应 webpack4)里,webpack-dev-server 命令一运行,会报无法找到模块 webpack-cli/bin/config-yargs 错误,因为 webpack-cli4 已经去除了模块 webpack-cli/bin/config-yargs,如果想用 webpack-dev-server 命令,则需要降级为 webpack-cli3,否则使用 webpack server 命令代替。

当时 webpack4 刚升级 webpack5 那会,我就发现了这个问题,但 webpack 文档也明显写着是使用 webpack-dev-server(估计没有及时更改),在百度也找不到解决方法,后面在 github 的 webpack 的 issue 发现了这个问题的解决方法。所以,大家如果发现问题,可以多点查或提 github 的 issue,这是个很不错的方法。

  • 2021.9.18 补充 现在最新的版本,好像已经没有这个问题了,webpack-dev-server 和 webpack server 命令均可以用,可能是官方为了兼容,改回来了。不过建议在新版本里使用 webpack server 命令。

这个问题的相关讨论,具体可以看这两个网站:

  1. Cannot find module 'webpack/bin/config-yargs' - Stack Overflow
  2. Error: Cannot find module 'webpack-cli/bin/config-yargs' · Issue #2759 · webpack/webpack-dev-server (github.com)

完整代码

目录

webpack5 的使用(一):起步

webpack.config.js

const path = require('path')

const HtmlWebpackPlugin = require('html-webpack-plugin')
const { CleanWebpackPlugin } = require('clean-webpack-plugin')

module.exports = {
  // entry: path.resolve(__dirname, '../src/js/index.js'),
  entry: {
    main: path.resolve(__dirname, '../src/js/index.js'),
    header: path.resolve(__dirname, '../src/js/header.js'),
    footer: path.resolve(__dirname, '../src/js/footer.js'),
  },
  output: {
    // filename: 'main.js',
    filename: '[name].[fullhash].js',
    path: path.resolve(__dirname, '../dist')
  },
  devServer: {
    port: 3000,
    hot: true,
    contentBase: '../dist'
  },
  plugins: [
    // new HtmlWebpackPlugin({
    //   title: '首页'
    // }),
    // 配置多个 HtmlWebpackPlugin,有多少个页面就配置多少个
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../src/html/index.html'),
      filename: 'index.html',
      chunks: ['main'] // 与入口文件对应的模块名(entry 配置),这里可以理解为引入 main.js
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../src/html/header.html'),
      filename: 'header.html',
      chunks: ['header']
    }),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, '../src/html/footer.html'),
      filename: 'footer.html',
      chunks: ['footer']
    }),
    new CleanWebpackPlugin(),
  ]
}

package.json

{
  "name": "test",
  "version": "1.0.0",
  "description": "",
  "main": "index.js",
  "scripts": {
    "dev": "webpack server --config build/webpack.config.js --open",
    "build": "webpack --config ./build/webpack.config.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC",
  "devDependencies": {
    "clean-webpack-plugin": "^4.0.0-alpha.0",
    "html-webpack-plugin": "^5.3.1",
    "webpack": "^5.38.1",
    "webpack-cli": "^4.7.0",
    "webpack-dev-server": "^3.11.2",
  }
}

系列文章

转载自:https://juejin.cn/post/6969165512722890789
评论
请登录