9
头图

前言

我们在使用webpack时,经常会看到类似以下结构:

build
├── webpack.common.js
└── webpack.dev.js
└── webpack.prod.js

很多时候,webpack的配置我们基本复制粘贴过来的,没有想过为什么我们要把配置文件拆解成这么多。因此,当我们自己去学习配置webpack时,我们经常会出现以下等问题:

  • 开发环境构建速度慢
  • 打包后页面空白
  • 资源找不到

其实这些问题,都源于我们:

  • 不理解webpack构建开发环境、生产环境,两种环境配置的思想差异
  • 对两种环境输出的文件目录,脑海中没有一个清晰的理解

所以本文还是跟以前一样,不会一味的把配置复制过来,而是希望总结相关方法,让大家更好学会配置。

前期准备

由于讲的是配置,所以希望你对webpack有一些基础。如果你只是刚学习webpack,建议先阅读一下前两篇文章,尤其是第二篇

  1. 弄懂这几个概念后,我对webpack有了更新的理解:学习使用webpack时涉及到的一些概念,让我们对webpack整体有个大致的了解
  2. 有了这些方法,webpack你也可以自己配:总结配置webpack时的一些方法。通过这些方法,我们可以很好的理解webpack的一些基础配置该如何配置

学习大纲

这篇文章主要讲解:

  • webpack开发环境配置的核心思想
  • 根据核心思想,完成一个开发环境配置
  • 解析devServer配置项一些容易混淆的点
  • 总结webpack开发环境配置核心

备注

文章涉及到的案例已经上传到 github

  • 为了阅读方便,文章只贴了相关代码,建议fork一下,看看完整代码;或者跟着文章一起边看边敲,这样印象会更深刻一些
  • 创作不易,如果觉得有帮助的话,欢迎star🌟

开发环境核心思想

在上文我们提到,我们在使用webpack时,经常会看到类似以下目录:

build
├── webpack.common.js
└── webpack.dev.js
└── webpack.prod.js

为什么我们需要把配置文件拆解成这么多,那么繁琐呢?

我们先回顾一下,在我们在实际开发中,为了项目能够稳定安全上线,我们一般会分好几个环境:

  • 开发环境:在本地进行开发,调试的环境
  • 测试环境:我们在本地开发完成后,将代码部署到我们的测试服务器,进行测试
  • 生产环境:测试通过,将代码部署到正式服务器,正式上线
有些更严格的测试,还会有预生产环境等

我们的配置应该对环境具有针对性,因此不同的环境,我们的配置当然不能千篇一律。

目的

我们要先清楚开发环境根本的目的是什么。

开发环境的根本目的,就是在开发过程中,能快速定位到问题,更快能看到效果调试,提高开发效率。

尤其作为前端,离不开跟视觉打交道。我们巴不得Ctrl+S后,立马出效果,方便我们快速调试。试想一下,如果每次写完一个效果,要等上几秒钟才能看到,这会不会把我们逼疯?

思想

因此,为了能让我们尽快看到效果调试,减少webpack的编译过程,开发环境,配置应该一切从简

  • 对样式,我们不需要分离,直接用style-loader插入到<head />
  • jsimgmediafont等前端资源文件,不需要分包
  • 开启source map,方便定位问题
  • 使用webpack提供的devServer配置项,进行本地开发
  • 不要压缩代码
  • 不用没必要的loaderplugins
  • ...

开发环境配置,也因人而异,以上是我的做法。但是我们要记得,开发环境,配置应该一切从简,为了让我们能够更快看到效果,提高开发效率

开发环境配置

初体验

通过前一篇文章的讲解,相信大家对webpack的基础配置:

  • 处理css、less、前端资源等文件
  • 编译es6+语法及api
  • 处理html文件

已经掌握了相关的配置方法,并且我们还总结了一份基础的配置,不太清楚的同学可以看一下先,这个基础配置还是蛮重要的。

ok,那我们先用 learn-08 这个案例来体验一下如何进行本地开发调试。为了尽量贴近我们现实中开发的项目,案例里会:

  • html里面引用图片
  • 使用less里面引用图片
  • js里使用es6+,动态加载图片
  • 使用devServer配置项
为了阅读方便,具体的源码就不放文章了,大家可以去 github

然后进行以下步骤:

  1. 为了语义化,我们把webpack配置文件命名为webpack.dev.js
  2. 使用命令行启动webpack——npm start

    "scripts": {
     "start": "webpack server --config ./webpack.dev.js"
    }

运行结果:

devserve.png

我们会发现:

  • 文件编译处理完成后,不会输出任何文件
  • 此时开启了一个内部服务器(http://192.168.0.196:8080/)。如果我们的手机与电脑用的同个网络,用手机访问这个链接,就能看到效果了。这对调试H5开发是十分高效的(这主要归功于deveServer配置项,后文会有讲解)
  • 我们修改代码后,页面会实时更新

以上几乎是我们想要的高效开发效果。

分析

初步体验完后,我们根据上文总结的开发环境配置思想,来看看对开发环境该如何配置:

  • 解析样式不需要分离出css文件,我们直接将解析出来的样式插入到<header />中:

    module: {
      rules: [
          {
              test: /.(css|less)$/, 
              use: [
                  'style-loader',
                  'css-loader',
                  'less-loader'
              ]
          },
      ]
    },
  • jsimgmediafont等前端资源文件,不需要分包:

    output: {
      path: path.resolve(__dirname, './dist'),
      filename: '[name]-[chunkhash:5].js',
    },
    module: {
      rules: [
          {
              test: /\.(png|svg|jpg|jpeg|gif)$/i,
              type: 'asset',
              parser: {
                  dataUrlCondition: {
                      maxSize: 1024 * 3 // When the image size is < 3kb it will be converted to base64
                  }
              },
              generator: {
                  filename: '[name]-[hash:5][ext]' // Set the name of the output file
              }
          },
          {
              test: /\.m?js$/,
              exclude: /(node_modules|bower_components)/,
              use: {
                  loader: 'babel-loader'
              }
          }
      ]
    },
  • 开启source map,方便定位问题;并且不压缩代码:

    {
      mode: 'development',
      devtool: 'inline-cheap-module-source-map'
    }
  • 使用webpack提供的devServer进行本地开发:

    devServer: {
      static: {
          directory: path.join(__dirname, 'static'),
      },
    },
  • 没有安装其他多余的plugin,因为要解析html,所以只安装了解析htmlplugin

    plugins: [
      new HtmlWebpackPlugin({
          filename: path.resolve(__dirname, './dist/[name].html'),
          template: path.resolve(__dirname, './src/index.html'),
          title: 'webpack.dev.config',
      })
    ],

    我们对比一下基础配置,会发现开发环境配置跟基础配置几乎没差别,只是多使用了devServer配置项,来开启本地服务器调试:

// webpack.dev.js
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
+   mode: 'development',
+   devtool: 'inline-cheap-module-source-map',
    entry: {
        index: './src/index.js'
    },
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: '[name]-[chunkhash:5].js',
    },
    module: {
        rules: [
            {
                test: /.(css|less)$/, 
                use: [
                    'style-loader',
                    'css-loader',
                    'less-loader'
                ]
            },
            {
                test: /\.(png|svg|jpg|jpeg|gif)$/i,
                type: 'asset',
                parser: {
                    dataUrlCondition: {
                        maxSize: 1024 * 3 // When the image size is < 3kb it will be converted to base64
                    }
                },
                generator: {
                    filename: '[name]-[contenthash:5][ext][query]' // Set the name of the output file
                }
            },
            {
                test: /\.m?js$/,
                exclude: /(node_modules|bower_components)/,
                use: {
                    loader: 'babel-loader'
                }
            }
        ]
    },
    plugins: [
        new HtmlWebpackPlugin({
            filename: path.resolve(__dirname, './dist/[name].html'),
            template: path.resolve(__dirname, './src/index.html'),
            title: 'webpack.dev.config',
        })
    ],
+   devServer: {
+       static: {
+           directory: path.join(__dirname, 'static'),
+       },
+   }
}

devServer

还记得我们之前的案例,是怎么运行我们的代码的吗?我们都是打包完以后,用自带的编辑器(vscode)运行查看结果的。要是我们平时开发是这么低效的话,那估计项目不用上线了。

因此webpack提供了一个十分人性化的配置项——devServer

想使用这个配置项,我们需要先npm i webpack-dev-server -D安装webpack-dev-server依赖

从这么语义化的名字就知道,它肯定是开发环境下,可以提供某种服务的配置。

这个服务就是,这将会开启一个本地服务,将我们配置的webpack,实时编译,保存在内存中,这样可以方便调试我们的代码,这很好的满足了我们本地开发需要高效的目的。

因此这个配置项,只用于我们开发环境配置

devServer.static

文档解释:告诉服务器从哪里提供内容。只有在你希望提供静态文件时才需要这样做

错误理解

devServe配置项,其实文档已经写的挺详细了,这里讲一个可能容易混淆的配置项——devServe.static

很多人使用webpack,都是复制粘贴,所以经常会看到下面这种配置:

output: {
    path: path.resolve(__dirname, './dist'),
}
devServer: {
    static: {
      directory: path.join(__dirname, 'dist'),
    }
}

因为我们设置的打包后输出的文件夹一般都是distdevServe.static配置项指定要提供的静态文件目录也是dist。所以,我们自然而然会以为,此时webpack开启的本地服务器访问的内容就是dist文件夹里面的内容。

因此,我们会得出错误的结论:devServe.static的作用就是,设置webpack开启的本地服务器时,访问的目录。

但是,我们可以看看上文的 dev.config.js,我们设置打包后输出的文件夹名称是distdevServe.static设置的目录是static。如果按照我们上文错误的理解,由于两个文件夹设置不同,此时我们服务器应该是404或者空白页面才对,但是我们依旧可以跑起我们的服务。

这说明devServe.static的作用,并不是设置webpack开启的本地服务器时,访问打包输出文件夹的目录。

正确理解

分析

我们继续看 learn-08 这个案例(static文件夹里面存放了logo.png图片)。

我们之前想在js里面引用相关图片,我们一般会这么做:

// index.js
const img = new Image();
img.src = require('Your image path');

我们一般是将图片根据相对路径require进来,此时图片相当于是一个模块(Module),因此这样图片会经过webpack编译打包(添加hash或者转成base64),最后写入到我们设置的最终目录(output.path)。

但是当我们设置了:

devServer: {
    static: {
      directory: path.join(__dirname, 'static'),
    }
}

开启本地服务器后,会有这一句提示:

Content not from webpack is served from 'your path/static' directory

首先,这说明我们设置的static这个目录,是不会经过webpack处理打包的,所以在这个文件夹里面的资源,是不会被webpack解析编译的,因此它也不会加上hash或转成base64

我们再来看看 learn-08index.js是如何使用static里的资源的:

// index.js
loadImage('./logo.png').then(img => {
    console.log('I am from index.js');
    img.width = 120;
    document.querySelector('#js_content .img_content').append(img);
});

我们会看到,我们是直接使用./的方式引入图片,说明webpack开启的本地服务器,会将我们设置的static的目录内容映射到根目录下。

用过vue-cli的同学应该能很好体会到,这其实就是vue-cli里面public文件夹的功能

我们可以用以下方式访问设置的devServer.static.directory文件夹里的内容:

  • 一般情况下devServer.static.directory会被映射到根目录,所以我们用http://[devServer.host]:[devServer.port]/[devServer.static.directory]访问
  • 如果想改变访问的路径,可以增加devServer.static.publicPath配置。此时可以用http://[devServer.host]:[devServer.port]/[devServer.static.publicPath]/[devServer.static.directory]访问

总结

经过上面的分析讲解,我们可以得出对devServer.static正确的理解应该是:

  • 它是设置一个存放,不经过webpack编译的静态资源目录(我们可以例如图片,第三方资源等),所以它不会被加上hash或者被转成base64;它是一个目录
  • 开启webpack本地服务器时,它一般会被映射到我们的项目的根目录下(可以通过devServe.static.publicPath修改访问目录)
  • 由于它不经过webpack编译打包,所以,我们最后一般会用copy-webpack-plugin,将devServer.static.directory复制到output.path根目录下
  • 它的功能就很像是vue-cli里面的public文件夹,我们开发的时候,可以通过./或者../访问到那个资源(具体看目录关系)

核心

好,通过上面对开发环境配置跟devServer的讲解,我们可以知道:

  • 开发环境配置一切从简,所以imgjs等资源会直接映射在根目录下(css被插入到<head />里了)
  • 开发环境webpack开启本地服务器后,也会将devServer.static.directory映射在根目录下

所以运行开发环境配置后,我们的结构目录大致如下:

dist
├── ecj-cli-b6fa8.png
├── index-c466b.js
├── index.html
└── logo.png

配置因人而异,最重要的是,我们配置完开发环境,生产环境后,对编译打包输出内容,目录,脑海中有一个很好地结构认识,这是非常重要的

这个目录结构也请大家牢记,后面的文章会用到

我们可以通过以下方法查看开发环境的结构目录:

  • devServer.devMiddleware.writeToDisk: true
  • http://[devServer.host]:[devServer.port]/webpack-dev-server
  • 谷歌浏览器F12 -> Sources

最后

  • 本篇文章学习了开发环境如何配置,下篇文章将会讲解配置生产环境前一些准备,让后续我们更好的学习生产环境配置
  • 感兴趣的同学,可以关注一下这个 👉 专栏
  • 文章涉及到的案例已经上传到 github,真的欢迎starfork学习

最后的最后,如果大家觉得文章有帮助到,创作不易,还请大家多点赞转发;如果有异同点,欢迎评论讨论。


limingcan
468 声望221 粉丝

Lee+= work hard + lucky