装webpack
npm i -D webpack webpack-cli @babel/cli @babel/core babel-loader babel-plugin-transform-runtime babel-preset-env copy-webpack-plugin terser-webpack-plugin
太长不看版:
const path = require('path');
const fs = require('fs');
const webpack = require('webpack');
const TerserPlugin = require("terser-webpack-plugin");
const CopyPlugin = require("copy-webpack-plugin");
const PATHS = {
src: path.resolve(__dirname, 'src'),
release: path.resolve(__dirname, 'dist')
}
const nodeModules = {};
fs.readdirSync('node_modules')
.filter((nModule) => !['.bin'].includes(nModule))
.forEach((nModule) => {
nodeModules[nModule] = nModule;
});
module.exports = {
mode: 'production',
entry: path.resolve(__dirname, 'app.js'),
output: {
filename: 'bundle.js',
path: PATHS.release,
library: {
type: 'commonjs'
}
},
target: 'node',
externals: nodeModules,
context: __dirname,
node: {
__filename: false,
__dirname: false
},
module: {
rules: [
{
test: /\.js$/,
exclude: [/node_modules/, ]
loader: 'babel-loader',
options: {
presets: [
[
'env', {
'targets': {
node: '6.10'
}
}
]
],
},
}
],
},
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': '"production"',
'process.env.PORT': '8080',
}),
new CopyPlugin({
patterns: [
{ from: path.resolve(__dirname, 'install.js'), to: path.resolve(PATHS.release, 'install.js') },
{ from: path.resolve(__dirname, 'uninstall.js'), to: path.resolve(PATHS.release, 'uninstall.js') },
{ from: path.resolve(__dirname, 'package.json'), to: path.resolve(PATHS.release, 'package.json') },
],
}),
],
optimization: {
minimize: true,
minimizer: [new TerserPlugin({
test: /\.js(\?.*)?$/i,
})],
},
resolve: {
extensions: ['.js', '.json']
}
}
-------- 正文分割线 --------
首先分析你的后端代码,
不需要打包: node_modules
需要打包: src/.js, src/.json, package.json, install.js(把nodejs后端注册成service), uninstall.js(从service里remove掉我的nodejs后端)
module.exports = {
mode: 'production', // 后端的运行环境: production, development, none, webpack对每个环境都有对应的处理逻辑,具体看官网: https://www.webpackjs.com/concepts/#mode
entry: path.resolve(__dirname, 'app.js'), //入口. webpack打包出来的bundle.js实际上是一个立即执行程序,entry是告诉webpack从哪里开始构建. 官网介绍:https://www.webpackjs.com/concepts/#entry
output: {
filename: 'bundle.js', // 把你的后端打包成一个叫bundle.js的文件
path: PATHS.release, // bundle.js 应该放在哪里
// libraryTarget: 'commonjs' //我的后端是js. 官网说以后libraryTarget会改成library.type: https://www.webpackjs.com/configuration/output/#outputlibrarytarget
library: {
type: 'commonjs'
}
},
target: 'node', // 我这是nodejs 后端,所以我选了node,前端用的react18,框架自带webpack.config里, target选的是browserslist,具体选项参看官网https://www.webpackjs.com/configuration/target/
externals: nodeModules, //像是const axios = require('axios)这种语句,默认webpack会把node_modules/axios打包进来,我们不想让bundle.js太大,就得告诉webpack别打包,等runtime的时候再去引用. 如果你引用别的项目的可执行文件,你的externals就不止node_modules下面的东西了. 官网介绍: https://www.webpackjs.com/configuration/externals/
context: __dirname, // 入口文件的folder的绝对路径,其实我不太理解为啥给了entry还得给context,不过官网说是就是吧,https://www.webpackjs.com/configuration/entry-context/
node: { // 设置为true: bundle.js里暴露你真实的文件名和路径 https://webpack.docschina.org/configuration/node/
__filename: false,
__dirname: false
},
module: {
rules: [
{
test: /\.js$/,
exclude: [/node_modules/, ]
loader: 'babel-loader',
options: {
presets: [
[
'env', {
'targets': {
node: '6.10'
}
}
]
],
},
}
],
},
plugins: [
new webpack.DefinePlugin({ // 定义全局变量 https://webpack.js.org/plugins/define-plugin/
'process.env.NODE_ENV': '"production"',
'process.env.PORT': '8080',
}),
new CopyPlugin({ // 把不需要打包,需要单独存放的文件copy去dist文件夹里. 我这里copy的是把后端注册成service的install.js, 把后端从service remove掉的uninstall.js, 还有package.json, 因为对install.js的调用写在package.json里面, 官网:https://webpack.js.org/plugins/copy-webpack-plugin/
patterns: [
{ from: path.resolve(__dirname, 'install.js'), to: path.resolve(PATHS.release, 'install.js') },
{ from: path.resolve(__dirname, 'uninstall.js'), to: path.resolve(PATHS.release, 'uninstall.js') },
{ from: path.resolve(__dirname, 'package.json'), to: path.resolve(PATHS.release, 'package.json') },
],
}),
],
optimization: { // webpack会根据mode来优化bundle, 不过你也可以自己通过optimizaion来设置, https://webpack.docschina.org/configuration/optimization/
minimize: true, // 用minimizer来压缩bundle
minimizer: [new TerserPlugin({
test: /\.js(\?.*)?$/i,
})],
},
resolve: { // https://webpack.docschina.org/configuration/resolve
extensions: ['.js', '.json']
}
}
自此, webpack.config.js配完了, 正常来说, 你在package.json添加一项
"scripts": {
...,
"build": "webpack --config webpack.config.js"
}
然后npm run build 就完事了. 但是我得配jekins, 所以我得在js里面webpack --config webpack.config.js, 等webpack打包完, 还得压缩成zip, 然后上传服务器, 所以继续改代码:
const build = () => {
const argv = require('yargs').argv;
const env = argv?.['env'] || 'PRD'; // 从外部接参 node deploy.js --env=PRD
const webpackConfig = env === 'DEV' ? 'webpack.dev.config.js' : 'webpack.config.js';
// 跑"webpack --config webpack.config.js"
const cmd = util.promisify(child_process.exec);
(async () => {
await (cmd(`webpack --config ${webpackConfig}`));
})();
// 下面比较猥琐, 用setInterval + fs.lstatSync(bundlePath, {throwIfNoEntry: false})?.isFile() 来判断bundle.js究竟生成了没有. 具体代码涉密就不提供了
}
const compress = () => {
// 用了archiver 包, 具体代码涉密也不写了, 官网写的也蛮清楚的了, 自取吧
// https://www.npmjs.com/package/archiver
}
(async () => {
await build();
await compress();
await upload();
})()
上传到server之后, 用node-windows发布到service里面; 或者用pm2编译成exe, 运行exe, 可以在task manager里面找到.