Node.js + Webpack5 后端开发 构建自动重载服务器

Webpack5的变化

  1. 前端开发变化, 开箱即用webpack serve命令,只需要安装webpack-dev-server就可以直接启用了。
$ webpack serve --help
Usage: webpack s | serve
Description: Run the webpack Dev Server

此时,npx webpack-dev-server命令会报错,因此它只兼容Webpack4,不过Webpack5可以使用它(webpack serve命令就是调用它):

$ npx webpack-dev-server
Cannot find module 'webpack-cli/bin/config-yargs'
Require stack:
- C:UserslyDesktopTypeScript
ode_moduleswebpack-dev-serverinwebpack-dev-server.js

webpack-node-externals库

使用Webpack开发后端时,通常不希望捆绑node_modules下的依赖项。该库创建了一个外部函数,使Webpack中捆绑时将忽略node_modules下的模块。
Github:https://github.com/liady/webpack-node-externals
安装:

npm install webpack-node-externals -D
yarn add webpack-node-externals -D

原理:externals作为一个函数使用 -- https://webpack.js.org/configuration/externals/#function

        externals: [
            // 'express',
            function ({ context, request }, callback) { // 官网和CLI提示不一致,此处遵循CLI标准
                console.log(`${context} => ${request}`); // 打印import和require请求
                callback(); // 通过请求
            },
        ],

例子:该函数过滤express模块,该模块的导出语句直接替换为require('express')

            function ({ context, request }, callback) {
                if (!context.match(/.*node_modules.*/)) {
                    console.log(`请求:${context} => ${request}`);
                    if (request === 'express') {
                        callback(null, `require('express')`); // 直接编码`const express = ?`赋值语句的右值
                    } else {
                        callback();
                    }
                } else {
                    console.log(`其它:${context} => ${request}`);
                    callback();
                }
            },

该怎么实现webpack-node-externals库的功能呢?

观察发现express导致了更多的require请求,这些请求的上下文都是在node_modules目录下,但是不能拒绝这些请求,否则无法生存dist:

                    console.log(`其它:${context} => ${request}`);
                    // callback(); 忽略请求,编译被中断


其实,对于node_modules目录下的请求,使用require('${contextByNode_Modules}/${request}')语句是可以减轻编译重量的:

        externals: [
            // 'express',
            function ({ context, request }, callback) { // 官网和CLI提示不一致,此处遵循CLI标准
                if (!context.match(/.*node_modules.*/)) {
                    console.log(`导入:${context} => ${request}`);
                    callback();
                } else {
                    let contextByNode_Modules = context.match(/.*node_modules[/\](.*)$/)[1];
                    console.log(`其它:${context} => ${request}`);
                    let cmd = `require('${contextByNode_Modules}/${request}')`;
                    console.log({ cmd });
                    callback(null, cmd);
                }
            },
        ],

但是这些模块还是被Webpack解析了(例中的express),并且被部分绑定(哭),达不到“由宿主提供提供该库”的要求。

相对合理的解决方案

            function ({ context, request }, callback) { // 官网和CLI提示不一致,此处遵循CLI标准
                console.log(`导入:${context} => ${request}`);
                // return callback(); // 临时关闭函数以测试
                // 排除node_modules模块以及loader
                if (!path.isAbsolute(request) && !request.match(/^./)) { // require目标不是绝对路径,且不以dot开头,则大概率就是node_modules请求。
                    // 要排除入口,直接遍历config.entry字段似乎不太可行,因为有隐含规则,比如"./src/index.js"。
                    // 上下文不可以是cwd,或者__dirname,从而排除入口(此处担心入口是绝对路径,且不以dot开头,这样会造成编译完成但运行时找不到模块)
                    if (context !== process.pwd && context !== __dirname) {
                        // 还有一种情况:在import或require语句中指定了loader,而指定方式又有强制与非强制的区别。
                        // 一般来说,即便这些依赖项可以在运行时加载,不过我们也希望进行编译打包,从而方便开发
                        // 如果指定了loader,则一定含有感叹号!这种情况需要排除掉
                        if (!request.includes('!')) {
                            // 替换node_modules依赖请求
                            let instruction = `require('${request}')`;
                            console.log('运行时依赖:', `${request}由node_modules提供 => ${request} = ${instruction}`.green);
                            return callback(/*没有错误*/null, instruction);
                        }
                    }
                }
                return callback();
            },

自动重载以应用代码更新

Github: https://github.com/develon2015/node-dev-server
想必大家都知道前端开发工具: webpack-dev-server, 本人实现了一个类似的功能, 不过它在后端开发中发挥作用!

值得一提的是,@nest/cli也是使用的webpack实现,并且也使用了第三方开源库设置externals来排除node_modules模块。

原文地址:https://www.cnblogs.com/develon/p/13852019.html