接上篇: 实战 webpack 4 配置解析二
现在让我们看看我们的 webpack.dev.js
配置文件,它包含了我们项目开发时用于开发构建的所有设置。它与 webpack.common.js
中的设置合并形成了一个完整的webpack 配置。
// webpack.dev.js - developmental builds
const LEGACY_CONFIG = 'legacy';
const MODERN_CONFIG = 'modern';
// node modules
const merge = require('webpack-merge');
const path = require('path');
const sane = require('sane');
const webpack = require('webpack');
// webpack plugins
const Dashboard = require('webpack-dashboard');
const DashboardPlugin = require('webpack-dashboard/plugin');
const dashboard = new Dashboard();
// config files
const common = require('./webpack.common.js');
const pkg = require('./package.json');
const settings = require('./webpack.settings.js');
在前面部分,我们还是先引入我们需要的 Node 包,以及我们使用的 webpack 插件。然后我们将 webpack.settings.js
导入,以便我们可以访问那里的配置,并将 package.json
作为 pkg
导入,以便访问那里的一些配置。
我们还导入 webpack.common.js
公共 webpack 配置,用来合并我们的开发环境的配置。
看看 configureDevServer()
长什么样:
// Configure the webpack-dev-server
const configureDevServer = (buildType) => {
return {
public: settings.devServerConfig.public(),
contentBase: path.resolve(__dirname, settings.paths.templates),
host: settings.devServerConfig.host(),
port: settings.devServerConfig.port(),
https: !!parseInt(settings.devServerConfig.https()),
quiet: true,
hot: true,
hotOnly: true,
overlay: true,
stats: 'errors-only',
watchOptions: {
poll: !!parseInt(settings.devServerConfig.poll()),
},
headers: {
'Access-Control-Allow-Origin': '*'
},
// Use sane to monitor all of the templates files and sub-directories
before: (app, server) => {
const watcher = sane(path.join(__dirname, settings.paths.templates), {
glob: ['**/*'],
poll: !!parseInt(settings.devServerConfig.poll()),
});
watcher.on('change', function(filePath, root, stat) {
console.log(' File modified:', filePath);
server.sockWrite(server.sockets, "content-changed");
});
},
};
};
当我们进行生产环境构建时,webpack 会绑定所有各种资产并将它们保存到文件系统中。相比之下,当我们在本地开发时,我们用 webpack-dev-server
来进行开发构建:
这类似于更复杂的 Browsersync 的变体,并大大提高了开发效率。
这里唯一有点不同的是我们使用 Sane 监视未通过 webpack 运行的文件(在本例中为我们的模板),以便在其中一个更改时执行整页重新加载。
请注意,webpack-dev-server
的配置仍然来自我们的 webpack.settings.js
文件。对于很多人来说默认值可能已经够用了,但是我使用 Laravel Homestead 作为本地开发人员,正如 Local Development with Vagrant / Homestead 这篇文章中所讨论的那样。这意味着我在我的 Homestead VM 中运行所有开发工具。
因此,不要在我的 webpack.settings.js
文件中对本地开发环境进行硬编码(因为它可能因团队中的人而异),webpack.settings.js
可以从一个可选的 .env
文件中读取拥有特定的 devServer
配置:
# webpack example settings for Homestead/Vagrant
DEVSERVER_PUBLIC="http://192.168.10.10:8080"
DEVSERVER_HOST="0.0.0.0"
DEVSERVER_POLL=1
DEVSERVER_PORT=8080
DEVSERVER_HTTPS=0
您可能使用有别与我,所以根据你的需要把 .env
文件改成适合你的配置。dotenv
背后的思想是我们在 .env
文件中配置了一个特定于环境的东西,我们不会将它提交到我们的 git 仓库。如果 .env 文件不存在,那也很好,使用默认值就好了:
devServerConfig: {
public: () => process.env.DEVSERVER_PUBLIC || "http://localhost:8080",
host: () => process.env.DEVSERVER_HOST || "localhost",
poll: () => process.env.DEVSERVER_POLL || false,
port: () => process.env.DEVSERVER_PORT || 8080,
https: () => process.env.DEVSERVER_HTTPS || false,
},
下面是 configureImageLoader()
:
// Configure Image loader
const configureImageLoader = (buildType) => {
if (buildType === LEGACY_CONFIG) {
return {
test: /\.(png|jpe?g|gif|svg|webp)$/i,
use: [
{
loader: 'file-loader',
options: {
name: 'img/[name].[hash].[ext]'
}
}
]
};
}
if (buildType === MODERN_CONFIG) {
return {
test: /\.(png|jpe?g|gif|svg|webp)$/i,
use: [
{
loader: 'file-loader',
options: {
name: 'img/[name].[hash].[ext]'
}
}
]
};
}
};
我们传入 buildType
,以便我们可以返回不同的结果,具体取决于它是旧版构建还是新版构建。在这个例子中,我们返回了相同的配置,但这也很可能会变。
需要重点注意的是这仅适用于我们的 webpack 构建中包含的图像;很多其他图像都来自其他地方(CMS系统,资产管理系统等)。
要让 webpack 处理图像,请需要将其导入 JavaScript:
import Icon from './icon.png';
有关详细信息,请查看 webpack 文档关于 “加载图像” 的部分。
下面是我们 configurePostcssLoader()
函数:
// Configure the Postcss loader
const configurePostcssLoader = (buildType) => {
// Don't generate CSS for the legacy config in development
if (buildType === LEGACY_CONFIG) {
return {
test: /\.(pcss|css)$/,
loader: 'ignore-loader'
};
}
if (buildType === MODERN_CONFIG) {
return {
test: /\.(pcss|css)$/,
use: [
{
loader: 'style-loader',
},
{
loader: 'vue-style-loader',
},
{
loader: 'css-loader',
options: {
importLoaders: 2,
sourceMap: true
}
},
{
loader: 'resolve-url-loader'
},
{
loader: 'postcss-loader',
options: {
sourceMap: true
}
}
]
};
}
};
我们使用 PostCSS 来处理所有 CSS,包括 Tailwind CSS。我认为它是 CSS 的Babel,因为它将各种高级 CSS 功能编译成您的浏览器可以理解的普通 CSS。
需要要注意的是,对于 webpack 加载器,它们处理的顺序与它们列出的顺序相反:
url()
重写为相对公共路径。@import
和 url()
。.vue
单文件组件中内联的所有样式注入 CSS 文件。
内联标签的文档中。记住,因为这是在本地开发所做的事情,所以我们不需要做任何多余的事情将所有 CSS 提取到最小化文件中。相反,我们只是让 style-loader
在我们的文档中内联它。
webpack-dev-server
将会对 CSS 使用热模块更换(HMR),因此不论什么时候我们更改内容,它都会自动重新构建和注入 CSS。这还是有点神奇。
我们通过包含它来告诉 webpack 处理 CSS:
import styles from '../css/app.pcss';
这个在 webpack 的文档 Loading CSS 这节有更详细的讨论。
我们从 App.js
入口点开始;将此视为 PostCSS
的切入点。app.pcss
文件 @import
我们项目使用的所有CSS;稍后将详细介绍。
最后,module.exports
使用 webpack-merge
将 webpack.common.js
中的common.legacyConfig
与我们的开发旧版配置合并,并将 common.modernConfig
与我们的开发新版配置合并:
// Development module exports
module.exports = [
merge(
common.legacyConfig,
{
output: {
filename: path.join('./js', '[name]-legacy.[hash].js'),
publicPath: settings.devServerConfig.public() + '/',
},
mode: 'development',
devtool: 'inline-source-map',
devServer: configureDevServer(LEGACY_CONFIG),
module: {
rules: [
configurePostcssLoader(LEGACY_CONFIG),
configureImageLoader(LEGACY_CONFIG),
],
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
],
}
),
merge(
common.modernConfig,
{
output: {
filename: path.join('./js', '[name].[hash].js'),
publicPath: settings.devServerConfig.public() + '/',
},
mode: 'development',
devtool: 'inline-source-map',
devServer: configureDevServer(MODERN_CONFIG),
module: {
rules: [
configurePostcssLoader(MODERN_CONFIG),
configureImageLoader(MODERN_CONFIG),
],
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new DashboardPlugin(dashboard.setData),
],
}
),
];
通过在 module.exports
中返回一个数组,我们告诉 webpack 我们需要完成多个编译:一个用于我们的旧版构建,另一个用于我们的新版构建。
需要注意,对于旧版构建,我们将处理后的 JavaScript 输出为 [name]-legacy.[hash].js
,而新版构建将其输出为 [name].[hash].js
。
通过将 mode
设置为 ‘development
’,我们告诉 webpack 这是开发版本的构建。
通过将 devtool
设置为 ‘inline-source-map
’,我们要求将 CSS/JavaScript 的 .map
内联到文件中。这使文件变得庞大,但它便于调试。
webpack.HotModuleReplacementPlugin 用来支持 Webpack 的热模块替换(HMR)。
DashboardPlugin
插件让我们感觉自己像一个宇航员,盯着酷炫的 webpack 构建面板:
我发现 DashboardPlugin
开发 HUD
(Head Up Display 平视显示器)比默认的webpack 进度滚动更有用。
就这样,我们现在为我们的项目提供了很棒的开发构建环境。
下篇:
实战 webpack 4 配置解析四