前言
我们在使用webpack
时,经常会看到类似以下结构:
build
├── webpack.common.js
└── webpack.dev.js
└── webpack.prod.js
很多时候,webpack
的配置我们基本复制粘贴过来的,没有想过为什么我们要把配置文件拆解成这么多。因此,当我们自己去学习配置webpack
时,我们经常会出现以下等问题:
- 开发环境构建速度慢
- 打包后页面空白
- 资源找不到
其实这些问题,都源于我们:
- 不理解
webpack
构建开发环境、生产环境,两种环境配置的思想差异 - 对两种环境输出的文件目录,脑海中没有一个清晰的理解
所以本文还是跟以前一样,不会一味的把配置复制过来,而是希望总结相关方法,让大家更好学会配置。
前期准备
由于讲的是配置,所以希望你对webpack
有一些基础。如果你只是刚学习webpack
,建议先阅读一下前两篇文章,尤其是第二篇:
- 弄懂这几个概念后,我对webpack有了更新的理解:学习使用
webpack
时涉及到的一些概念,让我们对webpack
整体有个大致的了解 - 有了这些方法,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
插入到 - 对
js
、img
、media
、font
等前端资源文件,不需要分包 - 开启
source map
,方便定位问题 - 使用
webpack
提供的devServer
配置项,进行本地开发 - 不要压缩代码
- 不用没必要的
loader
跟plugins
- ...
开发环境配置,也因人而异,以上是我的做法。但是我们要记得,开发环境,配置应该一切从简,为了让我们能够更快看到效果,提高开发效率
开发环境配置
初体验
通过前一篇文章的讲解,相信大家对webpack
的基础配置:
- 处理
css、less
、前端资源等文件 - 编译
es6+
语法及api
- 处理
html
文件
已经掌握了相关的配置方法,并且我们还总结了一份基础的配置,不太清楚的同学可以看一下先,这个基础配置还是蛮重要的。
ok,那我们先用 learn-08 这个案例来体验一下如何进行本地开发调试。为了尽量贴近我们现实中开发的项目,案例里会:
- 在
html
里面引用图片 - 使用
less
里面引用图片 - 在
js
里使用es6+
,动态加载图片 - 使用
devServer
配置项
为了阅读方便,具体的源码就不放文章了,大家可以去 github 看
然后进行以下步骤:
- 为了语义化,我们把
webpack
配置文件命名为webpack.dev.js
使用命令行启动
webpack
——npm start
"scripts": { "start": "webpack server --config ./webpack.dev.js" }
运行结果:
我们会发现:
- 文件编译处理完成后,不会输出任何文件
- 此时开启了一个内部服务器(
http://192.168.0.196:8080/
)。如果我们的手机与电脑用的同个网络,用手机访问这个链接,就能看到效果了。这对调试H5
开发是十分高效的(这主要归功于deveServer
配置项,后文会有讲解) - 我们修改代码后,页面会实时更新
以上几乎是我们想要的高效开发效果。
分析
初步体验完后,我们根据上文总结的开发环境配置思想,来看看对开发环境该如何配置:
解析样式不需要分离出
css
文件,我们直接将解析出来的样式插入到
中:module: { rules: [ { test: /.(css|less)$/, use: [ 'style-loader', 'css-loader', 'less-loader' ] }, ] },
对
js
、img
、media
、font
等前端资源文件,不需要分包: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
,所以只安装了解析html
的plugin
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'),
}
}
因为我们设置的打包后输出的文件夹一般都是dist
,devServe.static
配置项指定要提供的静态文件目录也是dist
。所以,我们自然而然会以为,此时webpack
开启的本地服务器访问的内容就是dist
文件夹里面的内容。
因此,我们会得出错误的结论:devServe.static
的作用就是,设置webpack
开启的本地服务器时,访问的目录。
但是,我们可以看看上文的 dev.config.js,我们设置打包后输出的文件夹名称是dist
,devServe.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-08 的index.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
的讲解,我们可以知道:
- 开发环境配置一切从简,所以
img
、js
等资源会直接映射在根目录下(css
被插入到里了)
- 开发环境
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,真的欢迎
star
或fork
学习
最后的最后,如果大家觉得文章有帮助到,创作不易,还请大家多点赞转发;如果有异同点,欢迎评论讨论。