使用 Webpack 打包 node 程序,node_modules 真的被干掉啦

简介: 网上很多关于 webpack 打包 node 的文章,但是他们都是只打包你写的 node.js 的代码, node_modules 直接都被排除了,这样处理的话如果发布到线上

之前写过webpack打包webnodeelectron的文章,最后只写了打包web
因为当时觉得nodeelectron没必要打包,但是总有一些需求还是要打包的,例如代码混淆、压缩等等,所以这次就来写一下node的打包。

网上很多关于webpack打包node的文章,但是他们都是只打包你写的node.js的代码,node_modules
直接都被排除了,这样处理的话如果发布到线上,还是要将node_modules一起发布,这样就很麻烦了,所以这次我就来写一下如何将node_modules也打包进去。

1. 网上的文章的操作

网上查到的资料,大多数都是这样的操作:

const path = require('path');
const webpack = require('webpack');
const nodeExternals = require('webpack-node-externals');

module.exports = {
   
    mode: 'production',
    entry: './src/index.js',
    output: {
   
        path: path.resolve(__dirname, 'dist'),
        filename: 'index.js',
    },
    target: 'node',
    externals: [nodeExternals()],
};

就这么一丢丢代码,而且 100% 不会出问题,因为他使用了webpack-node-externals这个库,这个库的作用就是将node_modules排除掉,所以打包出来的文件就不会包含node_modules里面的代码了。

然后你发布到线上,必须要将node_modules一起发布,这样感觉打不打包区别不大,所以这种方式就没什么意义了。

webpack-node-externals这个库的作用就是将package.json里面的dependenciesdevDependencies
里面的包排除掉,所以打包出来的文件就不会包含node_modules里面的代码了。

externals这个配置项的作用就是排除掉一些包,不打包进去,这样打包出来的文件就会小一些。

2. 打包node_modules

通过上面的解释的意思,我们只需要将webpack-node-externals这个库去掉,然后将node_modules也打包进去就可以了。

const path = require('path');
const webpack = require('webpack');

module.exports = {
   
    mode: 'production',
    entry: './src/index.js',
    output: {
   
        path: path.resolve(__dirname, 'dist'),
        filename: 'index.js',
    },
    target: 'node',
};

是不是感觉配置很简单,然后执行npx webpack,然后等待打包完成,然后你就会发现,node_modules也被打包进去了,这样就可以直接发布到线上了。

3. node-gyp的排除

当然上面的方案还有其他的问题,例如node-gyp这种包,他是需要编译的,所以直接打包进去是不行的,所以我们需要将node-gyp这种包排除掉。

module.exports = {
   
    // ...
    externals: [
        function (context, request, callback) {
   
            if (/^node-gyp$/.test(request)) {
   
                return callback(null, 'commonjs ' + request);
            }
            callback();
        },
    ],
};

这样就可以将node-gyp排除掉了,然后你再次执行npx webpack,然后你就会发现,node-gyp这种包就不会被打包进去了。

除了node-gyp这种包,还有其他的包也需要排除,这个就要看你的项目了,如果你的项目里面有其他的包需要排除,那么你就需要自己去排除了。

module.exports = {
   
    // ...
    externals: [
        function (context, request, callback) {
   
            if (/^node-gyp$/.test(request)) {
   
                return callback(null, 'commonjs ' + request);
            }
            callback();
        },
        {
   
            // 可以手动排除
            'package-name': 'commonjs package-name',
        }
    ],
};

4. node-gyp的打包

当然我们的代码依赖了这些包,那么我们最终打包的时候排除了,那么我们的代码就会报错,所以我们需要将这些包编译出来,然后再打包进去。

当然node-gyp这种包是不能直接通过webpack打包的,我们可以直接通过copy-webpack-plugin这个插件将这些包拷贝到dist目录下面。

const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = {
   
    // ...
    plugins: [
        new CopyWebpackPlugin({
   
            patterns: [
                {
   
                    from: path.resolve(__dirname, 'node_modules/package-name'),
                    to: path.resolve(__dirname, 'dist/package-name'),
                },
            ],
        }),
    ],
};

这样就可以将node-gyp这种包拷贝到dist目录下面了,然后我们再次执行npx webpack,然后你就会发现,node-gyp这种包就被拷贝到dist目录下面了。

不过这样的话我们生产环境下的代码就需要将package.json也发布到线上了,因为我们的代码写的是包名,而不是包的路径,解决这个问题我们可以修改externals配置。

module.exports = {
   
    // ...
    externals: [
        {
   
            // 这里的 package-name 就是你的包名,index.js 就是你的包的入口文件,通常情况下会写到 package.json 的 main 字段里面
            'package-name': 'commonjs ./package-name/index.js',
        },
    ],
};

这样就可以将node-gyp这种包的路径指向dist目录下面了,然后我们再次执行npx webpack,然后你就会发现,node-gyp这种包就被指向dist目录下面了。

通常情况下应该很少会有node-gyp这种包,但是如果你的项目里面有的话,就需要这样处理了,不过我上面写的问题可能不是很全面,可能你还会遇到其他的问题,不管是什么问题,基本上都是包依赖的问题。

5. 外部配置文件

有时候我们的项目里面会有一些配置文件,比如config.json,这个文件里面会有一些配置,比如数据库的配置,这个我们喜欢放到外部,这样就可以手动修改,而不是每次都要重新打包。

这个时候我们还是可以通过copy-webpack-plugin这个插件将这些配置文件拷贝到dist目录下面。

const CopyWebpackPlugin = require('copy-webpack-plugin');

module.exports = {
   
    // ...
    plugins: [
        new CopyWebpackPlugin({
   
            patterns: [
                {
   
                    from: path.resolve(__dirname, 'config.json'),
                    to: path.resolve(__dirname, 'dist/config.json'),
                },
            ],
        }),
    ],
};

但是这样配置只是将这个文件拷贝到dist目录下面了,代码打包还是将这个文件打包进去了,这个时候有很多解决方案:

5.1. 使用nodefs模块

第一种是通过nodefs模块来读取这个文件,然后将这个文件的内容作为配置,这样就可以避免将这个文件打包进去了。

const fs = require('fs');
const config = JSON.parse(fs.readFileSync('./config.json', 'utf-8'));

这种方式的好处是不需要修改webpack的配置,但是缺点是每次都需要读取文件,这样会影响性能。

而且还需要开发环境和生产环境的目录结构一致,不然就会报错。

5.2. 使用webpackDefinePlugin

第二种是通过webpackDefinePlugin插件来定义一个全局变量,然后在代码里面通过process.env来获取这个全局变量,这样就可以避免将这个文件打包进去了。

const {
    DefinePlugin } = require('webpack');

module.exports = {
   
    // ...
    plugins: [
        new DefinePlugin({
   
            'process.env': {
   
                CONFIG: JSON.stringify(require('./config.json')),
            },
        }),
    ],
};

这种方式的好处是不需要修改代码,但是缺点是需要修改webpack的配置,而且使用方式也不太友好,需要同团队成员约定好。

5.3. 使用webpackexternals,将配置文件作为外部依赖

第三种可以通过webpackexternals来将这个文件指向dist目录下面,这样就可以避免将这个文件打包进去了。

module.exports = {
   
    // ...
    externals: [
        {
   
            './config.json': 'commonjs ./config.json',
        },
    ],
};

但是这种方式如果多个文件需要用,那么就需要配置多个externals,不过externals也支持正则,或者使用function来匹配。

module.exports = {
   
    // ...
    externals: [
        function (context, request, callback) {
   
            if (/config.json$/.test(request)) {
   
                return callback(null, 'commonjs ./config.json');
            }
            callback();
        },
    ],
};

这种方式是比较推荐的,因为不需要修改代码,团队成员也不需要约定,只需要修改webpack的配置就可以了。

6. 总结

上面就是关于webpack打包配置文件的一些方法,就这,respect!

目录
相关文章
|
4月前
|
JavaScript Java Serverless
函数计算产品使用问题之如何使用Node.js编写程序
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
4月前
|
消息中间件 JavaScript 中间件
函数计算产品使用问题之WebIDE编写的Node.js代码是否会自动进行打包部署
函数计算产品作为一种事件驱动的全托管计算服务,让用户能够专注于业务逻辑的编写,而无需关心底层服务器的管理与运维。你可以有效地利用函数计算产品来支撑各类应用场景,从简单的数据处理到复杂的业务逻辑,实现快速、高效、低成本的云上部署与运维。以下是一些关于使用函数计算产品的合集和要点,帮助你更好地理解和应用这一服务。
|
3月前
|
JavaScript
webpack打包TS
webpack打包TS
135 60
|
2月前
|
缓存 前端开发 JavaScript
Webpack 打包的基本原理
【10月更文挑战第5天】
|
2月前
|
前端开发 JavaScript
ES6模块化和webpack打包
【10月更文挑战第5天】
|
2月前
|
缓存 前端开发 JavaScript
深入了解Webpack:模块打包的革命
【10月更文挑战第11天】深入了解Webpack:模块打包的革命
|
3月前
|
JavaScript 测试技术 Windows
vue配置webpack生产环境.env.production、测试环境.env.development(配置不同环境的打包访问地址)
本文介绍了如何使用vue-cli和webpack为Vue项目配置不同的生产和测试环境,包括修改`package.json`脚本、使用`cross-env`处理环境变量、创建不同环境的`.env`文件,并在`webpack.prod.conf.js`中使用`DefinePlugin`来应用这些环境变量。
123 2
vue配置webpack生产环境.env.production、测试环境.env.development(配置不同环境的打包访问地址)
|
2月前
|
JavaScript 中间件 Shell
Node.js JXcore 打包
10月更文挑战第8天
33 1
|
2月前
|
缓存 前端开发 JavaScript
Webpack技术深度解析:模块打包与性能优化
【10月更文挑战第13天】Webpack技术深度解析:模块打包与性能优化
|
2月前
|
前端开发 JavaScript 开发者
深入了解Webpack:现代JavaScript应用的打包利器
【10月更文挑战第11天】 深入了解Webpack:现代JavaScript应用的打包利器