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

简介: 使用 Webpack 打包 node 程序,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里面的dependencies

devDependencies 里面的包排除掉,所以打包出来的文件就不会包含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!


目录
相关文章
|
1月前
|
JavaScript 前端开发
webpack成长指北第9章---webpack如何对icon字体进行打包
webpack成长指北第9章---webpack如何对icon字体进行打包
31 1
|
1月前
|
前端开发 JavaScript
webpack成长指北第7章---webpack的css\less\scss样式打包
webpack成长指北第7章---webpack的css\less\scss样式打包
42 0
|
1月前
|
前端开发 JavaScript
webpack成长指北第8章---webpack的CSS Modules打包
webpack成长指北第8章---webpack的CSS Modules打包
21 0
|
4月前
|
JavaScript 前端开发 Serverless
函数计算只支持Node.js,我用C++写的程序怎么运行?
函数计算只支持Node.js,我用C++写的程序怎么运行?
91 1
|
4月前
|
负载均衡 JavaScript 算法
Node.js 多进程的概念、原理、优势以及如何使用多进程来提高应用程序的性能和可伸缩性
Node.js 多进程的概念、原理、优势以及如何使用多进程来提高应用程序的性能和可伸缩性
43 1
|
4月前
webpack 使用打包报错 ERROR in node_modules\@types\node\ts4.8\assert.d.ts
webpack 使用打包报错 ERROR in node_modules\@types\node\ts4.8\assert.d.ts
116 0
|
3月前
|
存储 缓存 资源调度
深入浅出Node.js中的node_modules(二)
深入浅出Node.js中的node_modules
|
2天前
|
前端开发 JavaScript 开发者
深入了解Webpack:前端模块打包工具
深入了解Webpack:前端模块打包工具
8 1
|
4天前
|
JavaScript 前端开发
构建工具:配置Webpack打包Vue项目
【4月更文挑战第24天】本文介绍了如何配置Webpack来打包Vue项目。首先,Webpack作为模块打包器处理依赖并打包成可执行文件。接着,通过安装Node.js和npm,创建Vue项目,进入项目目录并配置Webpack的入口、输出、加载器和插件。最后,运行构建命令完成打包。理解Webpack基础并按需配置,能优化前端项目构建和开发体验。
|
3月前
|
存储 资源调度 JavaScript
深入浅出Node.js中的node_modules(三)
深入浅出Node.js中的node_modules