一套代码打包多个小程序实践
业务场景: 当前维护一个Taro小程序,页面、模块很多,部分功能之间可能并不相关。所以产品提出将该小程序中的部分模块抽离出来,重新打包一个小程序用来推广、拉新。
思考流程
Question & Answer
Q1. 不同小程序可能需要一起维护,不能每次改完这个,还要到另外一个项目中更改。
A1: 很好解决,直接在同一个项目中进行维护,不对具体模块进行拆分。
- 不同小程序的首页不同。在主体的小程序中,可能并不需要其他小程序中的首页。
A2: 首页的问题直接可以通过小程序打包的管理后台进行设置相应的路径,就可以设置首页了 或者 将首页路径配置为主包的第一个路径。
- 在其他小程序中也可能不需要主题小程序中的部分页面;聚合的小程序主包体积过大。
A3: 具体小程序不需要的页面在配置中把具体路径删除就不会打包了。
- 首页的路径需要根据具体小程序动态调整。
A4: 设置首页路径变量,该变量根据具体小程序进行判断设置。
- 不同小程序之间相关配置不同。
A5: 不同小程序设置不同的配置文件。
以上流程基本就是一次打包需要调整的东西了,但如果每次都这样就会让人很烦躁,而且如果有3个、4个...小程序需要同步维护呢!有没有什么方法优化?怎么优化? 思考ing... 打包之前要改这些文件,那么能不能在打包之前就让程序知道打包的是那个小程序,然后根据这个来判断?从这个思路走,就想到了在平时开发中的 process.env.NODE_ENV、还有通过环境配置 .env .env.developement .env.production等等,设置一些webpack的常量。如此,就清楚了具体需要如何去做接下来的流程。
具体实现流程
首先
process.env.NODE_ENV 的 production、development 是可以通过具体运行的 npm 脚本中 --mode development修改的,因此也通过这种方式在运行具体脚本时设置一个参数用来区分不同小程序。由于我这里是windows电脑,所以要安装cross-env来设置,具体命令如下:
json
"scripts": {
"build:weapp": "cross-env APP='TEST_APP' taro build --type weapp",
"dev:weapp": "npm run build:weapp -- --watch",
},
在 app.config.ts 文件中测试是否设置成功,
php
console.log('process.env', process.env.APP);
export default defineAppConfig({
pages: [
'pages/index/index'
],
window: {
backgroundTextStyle: 'light',
navigationBarBackgroundColor: '#fff',
navigationBarTitleText: 'WeChat',
navigationBarTextStyle: 'black'
}
})
运行 npm run dev:weapp 后,命令行出现如下结果,就说明设置成功了。 然后在主页面试试获取这个参数,用于去判断其他的代码逻辑。 但在运行时出现了这个错误。 发现是Nodejs中设置的运行时变量,打包后就没法获取了,因此要将这个参数设置为webpack中的一个常量,具体在 webpack 中可以使用 webpack.DefinePlugin 进行设置,但是在 taro 中并不需要这样做,可以直接在 config/index.ts 的配置中直接设置 env 的值。
具体代码如下:
需要注意的是,设置 env 的时候,具体的值需要通过JSON.stringify处理一下,不然会把process.env.APP的值当作一个变量。
ts
import { defineConfig, type UserConfigExport } from '@tarojs/cli'
import TsconfigPathsPlugin from 'tsconfig-paths-webpack-plugin'
import devConfig from './dev'
import prodConfig from './prod'
console.log('process.env.APP config', process.env.APP);
// https://taro-docs.jd.com/docs/next/config#defineconfig-辅助函数
export default defineConfig(async (merge, { command, mode }) => {
const baseConfig: UserConfigExport = {
projectName: 'taro-app-test',
date: '2024-1-12',
designWidth: 750,
deviceRatio: {
640: 2.34 / 2,
750: 1,
375: 2,
828: 1.81 / 2
},
env: {
APP: JSON.stringify(process.env.APP)
},
sourceRoot: 'src',
outputRoot: 'dist',
plugins: [],
defineConstants: {
},
copy: {
patterns: [
],
options: {
}
},
framework: 'react',
compiler: 'webpack5',
cache: {
enable: false // Webpack 持久化缓存配置,建议开启。默认配置请参考:https://docs.taro.zone/docs/config-detail#cache
},
mini: {
postcss: {
pxtransform: {
enable: true,
config: {
}
},
url: {
enable: true,
config: {
limit: 1024 // 设定转换尺寸上限
}
},
cssModules: {
enable: true, // 默认为 false,如需使用 css modules 功能,则设为 true
config: {
namingPattern: 'module', // 转换模式,取值为 global/module
generateScopedName: '[name]__[local]___[hash:base64:5]'
}
}
},
webpackChain(chain) {
chain.resolve.plugin('tsconfig-paths').use(TsconfigPathsPlugin)
}
},
h5: {
publicPath: '/',
staticDirectory: 'static',
output: {
filename: 'js/[name].[hash:8].js',
chunkFilename: 'js/[name].[chunkhash:8].js'
},
miniCssExtractPluginOption: {
ignoreOrder: true,
filename: 'css/[name].[hash].css',
chunkFilename: 'css/[name].[chunkhash].css'
},
postcss: {
autoprefixer: {
enable: true,
config: {}
},
cssModules: {
enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
config: {
namingPattern: 'module', // 转换模式,取值为 global/module
generateScopedName: '[name]__[local]___[hash:base64:5]'
}
}
},
webpackChain(chain) {
chain.resolve.plugin('tsconfig-paths').use(TsconfigPathsPlugin)
}
},
rn: {
appName: 'taroDemo',
postcss: {
cssModules: {
enable: false, // 默认为 false,如需使用 css modules 功能,则设为 true
}
}
}
}
if (process.env.NODE_ENV === 'development') {
// 本地开发构建配置(不混淆压缩)
return merge({}, baseConfig, devConfig)
}
// 生产构建配置(默认开启压缩混淆等)
return merge({}, baseConfig, prodConfig)
})
然后再次看首页能否拿到具体的 process.env.APP
这样下来已经差不多了,剩下的就是对动态打包进行处理的。
动态打包📦
经过如上流程,动态打包应该是很容易了,只需要通过 process.env.APP 的值在 app.config.ts 的配置文件中,动态的配置主包pages、分包pages...就能够动态打包了。了解具体需要怎么做,接下来就开始进行实践!
具体代码如下:
php
import { TEST_APP } from "./constants/app-type";
const pages = ["pages/index/index", "pages/bbb/index"];
const packageA_pages = ["pages/aaa/index", "pages/demo/index"]
if(process.env.APP === TEST_APP) {
pages.unshift("pages/test/index")
packageA_pages.push("pages/testa/index")
}
export default defineAppConfig({
pages: pages,
subPackages: [
{
root: "packageA",
pages: packageA_pages,
},
],
window: {
backgroundTextStyle: "light",
navigationBarBackgroundColor: "#fff",
navigationBarTitleText: "WeChat",
navigationBarTextStyle: "black",
},
});
接下来看下具体打包有什么差异。
正常打包后的文件目录:
配置过后打包的文件目录:
可以清楚的看到,在某个小程序中不需要的页面就没有被打包到该小程序中了,就这样解决了上面遇到的问题,开发完成发布时,也不需要去修改文件了,只需要对 app.config.ts 中进行相应的配置就可以了,而且还能够支持打包更多的小程序。
项目文件结构如下:
lua
├── __tests__
│ └── index.test.js
├── babel.config.js
├── config
│ ├── dev.ts
│ ├── index.ts
│ └── prod.ts
├── jest.config.ts
├── package.json
├── project.config.json
├── project.tt.json
├── src
│ ├── app.config.ts
│ ├── app.scss
│ ├── app.ts
│ ├── constants
│ │ └── app-type.ts
│ ├── index.html
│ ├── packageA
│ │ ├── components
│ │ └── pages
│ │ ├── aaa
│ │ ├── demo
│ │ └── testa
│ └── pages
│ ├── bbb
│ │ ├── index.config.ts
│ │ ├── index.module.scss
│ │ └── index.tsx
│ ├── index
│ │ ├── index.config.ts
│ │ ├── index.scss
│ │ └── index.tsx
│ └── test
│ ├── index.config.ts
│ ├── index.scss
│ └── index.tsx
├── tsconfig.json
├── types
│ └── global.d.ts
└── yarn.lock
总结
无用的废话哈哈哈。通过这次实践了解了一些关于打包流程上的东西,学习了打包命令中的参数配置,并解决了打包多个小程序中无用代码&...问题,也算是一个不小的收获吧。