实战 webpack 4 配置解析三

接上篇: 实战 webpack 4 配置解析二

WEBPACK.DEV.JS 解析

现在让我们看看我们的 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 配置,用来合并我们的开发环境的配置。

CON­FIG­U­RA­TION FUNTIONS(配置函数)

看看 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 来进行开发构建:

  • 启动本地的 Express web 服务为资源提供服务。
  • 为了速度,在内存构建我们的资源,而不是文件系统中。
  • 当我们更改 JavaScript,CSS,Vue组件等这些资源时,它们将会重新构建,但这不需要重新刷新页面,是通过热模块替换(HMR)将它们注入网页的。
  • 我们在更改模版时会重新加载页面。

这类似于更复杂的 Browsersync 的变体,并大大提高了开发效率。

这里唯一有点不同的是我们使用 Sane 监视未通过 webpack 运行的文件(在本例中为我们的模板),以便在其中一个更改时执行整页重新加载。

请注意,webpack-dev-server 的配置仍然来自我们的 webpack.settings.js 文件。对于很多人来说默认值可能已经够用了,但是我使用 Laravel Homestead 作为本地开发人员,正如 Local Devel­op­ment with Vagrant / Home­stead 这篇文章中所讨论的那样。这意味着我在我的 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 加载器,它们处理的顺序与它们列出的顺序相反:

  • postc­ss-loader  - 将文件加载并处理成 PostCSS。
  • resolve-url-loader - 将 CSS 中的任何 url() 重写为相对公共路径。
  • css-loader - 解决了我们所有的 CSS @importurl()
  • vue-style-loader - 把 .vue 单文件组件中内联的所有样式注入 CSS 文件。
  • style-loader - 将所有 CSS 注入到 <style></style> 内联标签的文档中。

记住,因为这是在本地开发所做的事情,所以我们不需要做任何多余的事情将所有 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.EXPORT (模块导出)

最后,module.exports 使用 webpack-mergewebpack.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 配置解析四

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值