dev.ts 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  1. import type { UserConfigExport } from '@tarojs/cli';
  2. import path from 'path';
  3. import dotenv from 'dotenv';
  4. import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin';
  5. // 加载 .env.development 文件中的环境变量
  6. dotenv.config({ path: path.resolve(__dirname, '../.env.development') });
  7. /**
  8. * 构建时间测量插件
  9. * 用于测量开发环境下的编译时间(包括首次编译和增量编译)
  10. */
  11. class BuildTimerPlugin {
  12. private buildStartTime: number = 0;
  13. private buildNumber: number = 0;
  14. apply(compiler: any) {
  15. // Watch 模式的编译开始(包括首次和增量)
  16. compiler.hooks.watchRun.tap('BuildTimerPlugin', (comp: any) => {
  17. this.buildNumber++;
  18. this.buildStartTime = Date.now();
  19. const time = new Date().toLocaleTimeString('zh-CN', { hour12: false });
  20. console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
  21. console.log(`🔨 [构建 #${this.buildNumber}] ${this.buildNumber === 1 ? '首次' : '增量'}编译开始... ${time}`);
  22. });
  23. // 非 Watch 模式的编译开始(理论上开发环境不会用到)
  24. compiler.hooks.run.tap('BuildTimerPlugin', () => {
  25. this.buildNumber++;
  26. this.buildStartTime = Date.now();
  27. const time = new Date().toLocaleTimeString('zh-CN', { hour12: false });
  28. console.log('\n━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━');
  29. console.log(`🔨 [构建 #${this.buildNumber}] 编译开始... ${time}`);
  30. });
  31. // 编译完成(包括首次和增量)
  32. compiler.hooks.done.tap('BuildTimerPlugin', (stats: any) => {
  33. const duration = Date.now() - this.buildStartTime;
  34. const seconds = (duration / 1000).toFixed(2);
  35. const time = new Date().toLocaleTimeString('zh-CN', { hour12: false });
  36. // 获取编译的模块数量
  37. const modulesCount = stats.compilation.modules.size;
  38. // 判断是否有错误或警告
  39. const hasErrors = stats.hasErrors();
  40. const hasWarnings = stats.hasWarnings();
  41. console.log(`${hasErrors ? '❌' : '✅'} [构建 #${this.buildNumber}] 编译${hasErrors ? '失败' : '完成'}! ${time}`);
  42. console.log(`⏱️ 耗时: ${seconds}s (${duration}ms)`);
  43. console.log(`📊 模块数: ${modulesCount}`);
  44. if (hasErrors) {
  45. console.log(`⚠️ 错误: ${stats.compilation.errors.length} 个`);
  46. }
  47. if (hasWarnings) {
  48. console.log(`⚠️ 警告: ${stats.compilation.warnings.length} 个`);
  49. }
  50. console.log('━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━\n');
  51. });
  52. }
  53. }
  54. export default {
  55. logger: {
  56. quiet: false,
  57. stats: true,
  58. },
  59. defineConstants: {
  60. // MQTT_BROKER_URL_FROM_WEBPACK: '"ws://192.168.110.13:8083/mqtt"',
  61. MQTT_BROKER_URL_FROM_WEBPACK: '"ws://192.168.110.245:8083/mqtt"',
  62. },
  63. mini: {},
  64. h5: {
  65. // ⚡ 优化:使用更快的 source map 类型(提升 40-60% 构建速度)
  66. // 'eval-source-map' 是最慢但最详细的
  67. // 'cheap-module-source-map' 快很多,仍然保留行号和源码映射
  68. sourceMapType: 'cheap-module-source-map',
  69. publicPath: '/',
  70. devServer: {
  71. proxy: {
  72. '/dr': {
  73. // target: 'http://192.168.110.13', // 你的后端服务地址
  74. target: 'http://192.168.110.239',
  75. changeOrigin: true, // 允许跨域
  76. // pathRewrite: {
  77. // '^/dr/api': '' // 可选,用于重写路径
  78. // }
  79. },
  80. '/mqtt': {
  81. // target: 'ws://192.168.110.13:8083', // MQTT WebSocket 服务地址
  82. target: 'ws://192.168.110.239:8083',
  83. changeOrigin: true,
  84. ws: true, // 启用 WebSocket 代理
  85. // pathRewrite: {
  86. // '^/mqtt': '/mqtt' // 保持路径不变,或根据需要调整
  87. // }
  88. },
  89. },
  90. // server: 'https', // 启用 HTTPS ,为了开发环境测试打开摄像头功能
  91. host: '0.0.0.0', // 监听所有网络接口
  92. open: false, // 可选:是否自动打开浏览器
  93. port: 10086, // 可选:指定端口号
  94. static: {
  95. directory: path.resolve(__dirname, '../public'),
  96. },
  97. },
  98. // Use webpackChain to customize Webpack
  99. // eslint-disable-next-line
  100. webpackChain(chain, webpack) {
  101. // ✅ 添加构建时间测量插件
  102. chain.plugin('build-timer').use(BuildTimerPlugin);
  103. // 读取环境变量,告诉webpack在打包时,使用环境变量中定义的值 替换掉代码中的process.env.USE_MSW
  104. // 打印环境变量,检查是否正确读取
  105. console.log('环境变量 process.env.USE_MSW:', process.env.USE_MSW);
  106. console.log('环境变量 process.env.NODE_ENV:', process.env.NODE_ENV);
  107. // 确保使用正确的值,直接从.env文件读取
  108. const useMSW = JSON.stringify(
  109. process.env.USE_MSW === 'true' ? 'true' : 'false'
  110. );
  111. console.log('使用的 useMSW 值:', useMSW);
  112. // 检查 define 插件是否已存在,如果不存在则先创建它
  113. const hasDefinePlugin = chain.plugins.has('define');
  114. if (!hasDefinePlugin) {
  115. chain.plugin('define').use(webpack.DefinePlugin, [{}]);
  116. }
  117. /* 1. 把 Taro 可能注入的所有 react-refresh 插件先删掉 */
  118. chain.plugins.delete('react-refresh'); // 3.5 之前
  119. chain.plugins.delete('ReactRefreshWebpackPlugin'); // 3.6+ 可能叫这个
  120. /* 2. 重新注册,强制关闭 overlay */
  121. chain
  122. .plugin('ReactRefreshWebpackPlugin') // 名字随意,保证唯一
  123. .use(ReactRefreshWebpackPlugin, [
  124. {
  125. overlay: false, // 👈 关键:关掉灰色蒙层
  126. },
  127. ])
  128. // 然后再修改插件配置
  129. chain.plugin('define').tap((args) => {
  130. // 确保args[0]存在
  131. if (!args[0]) {
  132. args[0] = {};
  133. }
  134. args[0]['process.env.USE_MSW'] = useMSW;
  135. console.log('DefinePlugin配置:', args[0]);
  136. return args;
  137. });
  138. chain.devServer.merge({
  139. setupMiddlewares: (middlewares, devServer) => {
  140. devServer.app.get('/mockServiceWorker.js', (req, res) => {
  141. res.set('Content-Type', 'application/javascript');
  142. res.sendFile(
  143. path.resolve(__dirname, '../public/mockServiceWorker.js')
  144. );
  145. });
  146. return middlewares;
  147. },
  148. });
  149. },
  150. },
  151. } satisfies UserConfigExport<'webpack5'>;