prod-build.js 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300
  1. const path = require('path');
  2. const getEntry = require('./getEntry');
  3. const webpack = require('webpack');
  4. const webpackProdConfig = require('./webpack.prod.config.js');
  5. const hammer = require('./hammer');
  6. const HtmlWebpackPlugin = require('html-webpack-plugin');
  7. const config = require('../new-config.json');
  8. const CleanWebpackPlugin = require('clean-webpack-plugin');
  9. const CopyPlugin = require('copy-webpack-plugin');
  10. const getVersion = require('./version');
  11. const dependjsConf = require('../dependjs.json');
  12. Object.assign(config, dependjsConf);
  13. // 项目根目录
  14. const projectPath = path.join(__dirname, '../');
  15. // 输入参数,hrhi hrwa 什么的
  16. const inputParam = [].slice.call(process.argv, 2);
  17. let runType = inputParam[0];
  18. if (runType === 'patch') {
  19. inputParam.shift();
  20. }
  21. // 参数拼装的正则,要是没有参数这个值为false
  22. // 页面入口对象和模版集合
  23. let entry = getEntry();
  24. // 模块入口对象
  25. let libEntry = getEntry('lib');
  26. // 入口对象
  27. let entryMap = entry.entry;
  28. // 自定义模版map
  29. let entryTemplateMap = entry.template;
  30. // 模块入口对象
  31. let libEntryMap = libEntry.entry;
  32. //过滤lib
  33. let libEntryMapModule = {};
  34. if (inputParam && inputParam.length > 0) {
  35. let reg = new RegExp(`^(${inputParam})`);
  36. for (let key in libEntryMap) {
  37. if (reg.test(key)) {
  38. libEntryMapModule[key] = libEntryMap[key];
  39. }
  40. }
  41. } else {
  42. libEntryMapModule = libEntryMap;
  43. }
  44. if (Object.keys(libEntryMapModule).length <= 0) {
  45. libEntryMapModule = libEntryMap;
  46. }
  47. // 临时中间变量,用于过滤参数选择的入口
  48. let midTrans = {};
  49. // 通过过滤入口的key值,找到对应的map
  50. Object.keys(entryMap).map((key) => {
  51. if (inputParam && inputParam.length > 0) {
  52. let ifCurrentKeyIsEntry = false;
  53. for (let p of inputParam) {
  54. if (key.includes(p)) {
  55. ifCurrentKeyIsEntry = true;
  56. break;
  57. }
  58. }
  59. if (ifCurrentKeyIsEntry) {
  60. midTrans[key] = entryMap[key];
  61. }
  62. } else {
  63. midTrans[key] = entryMap[key];
  64. }
  65. });
  66. // console.log('==== 入口 ====');
  67. if (Object.keys(midTrans).length > 0) {
  68. entryMap = midTrans;
  69. }
  70. // 拥有页面的入口的js对应的插件列表
  71. let pagePlugins = [...webpackProdConfig.plugins];
  72. // 没有页面的入口的js的对应的插件列表
  73. let libPlugins = [...webpackProdConfig.plugins];
  74. // 之后会切割入口文件以提升速度,这个变量就是存储切割后的入口数组
  75. let entryList = [];
  76. // 切割入口文件的时候用到的临时中转变量
  77. let cache = {};
  78. // 拿到所有入口的key值
  79. let entryMapKeysList = Object.keys(entryMap);
  80. // 所有的编译花费的时间数组
  81. let costTime = [];
  82. // 只运行一次的行为标志,主要用在了复制和clean插件上
  83. let firstTime = true;
  84. let allStartTime = Date.now();
  85. // 通过遍历,将数据量很大的入口对象,切割成每30个入口文件为一个的数组
  86. entryMapKeysList.map((key, index) => {
  87. cache[key] = entryMap[key];
  88. if (index % 20 === 0) {
  89. entryList.push(cache);
  90. cache = {};
  91. return;
  92. } else if (entryMapKeysList.length - 1 === index) {
  93. entryList.push(cache);
  94. }
  95. });
  96. // 运行链式的编译
  97. runList(entryList.shift());
  98. // 编译没有模板文件
  99. function libCompile() {
  100. let arr = [];
  101. config['copy'].map((key, index) => {
  102. if (inputParam && inputParam.length > 0) {
  103. for (let p of inputParam) {
  104. if (key['from'].includes(p)) {
  105. hammer.isFileExist(key.from) && arr.push(key);
  106. break;
  107. }
  108. }
  109. } else {
  110. if (!key['exclude']) {
  111. hammer.isFileExist(key.from) && arr.push(key);
  112. }
  113. }
  114. });
  115. // 复制操作是在模块编译这里进行
  116. libPlugins.push(new CopyPlugin(arr));
  117. if (Object.keys(libEntryMapModule).length <= 0) {
  118. console.log('总耗时:', Date.now() - allStartTime);
  119. return;
  120. }
  121. webpackProdConfig.entry = libEntryMapModule;
  122. webpackProdConfig.plugins = libPlugins;
  123. webpackProdConfig.output.filename = '[name].js';
  124. webpack(webpackProdConfig, (err, stats) => {
  125. if (err) {
  126. console.log(err);
  127. // throw new Error(err);
  128. return;
  129. }
  130. console.log(stats.toString({
  131. chunks: false, // Makes the build much quieter
  132. colors: true // Shows colors in the console
  133. }));
  134. let t = stats.endTime - stats.startTime;
  135. costTime.push(t);
  136. console.log('总耗时:', Date.now() - allStartTime);
  137. });
  138. }
  139. // 链式运行入口组
  140. function runList(entryMap) {
  141. compile(entryMap).then(() => {
  142. let entry = entryList.shift();
  143. if (entry) {
  144. runList(entry);
  145. } else if (runType !== 'patch') {
  146. libCompile();
  147. }
  148. });
  149. }
  150. // 根据一个map执行编译
  151. function compile(entryMap) {
  152. return new Promise((resolve, reject) => {
  153. let currentPlugin = [...pagePlugins];
  154. if (firstTime) {
  155. firstTime = false;
  156. currentPlugin.unshift(
  157. new CleanWebpackPlugin(['dist'], {
  158. root: path.join(__dirname, '../'),
  159. verbose: true,
  160. dry: false
  161. })
  162. );
  163. }
  164. // 根据入口配置添加html插件
  165. /*let configjs = ''; //额外配置的js文件
  166. let configcss = ''; //额外配置的css文件*/
  167. let externals = {};
  168. // dependjs: 依赖的js文件配置
  169. /*if (Array.isArray(config.dependjs)) {
  170. configjs += config.dependjs.map(src => {
  171. let moduleName = /(?:\.\.\/)*([^\.]*)\.js/.exec(src);
  172. if (moduleName && moduleName[1]) {
  173. externals[moduleName[1]] = moduleName[1];
  174. }
  175. return `<script src="${src}?v=${Date.now()}"></script>`;
  176. }).join('');
  177. }*/
  178. //优化依赖js方法,只有用到的时候才去添加
  179. // dependModuleName: 依赖的模块名
  180. if (Array.isArray(config.dependModuleName)) {
  181. // 打包时排除
  182. config.dependModuleName.forEach(item => (externals[`${item}`] = `${item}/index`));
  183. }
  184. // dependcss: 依赖的css文件配置
  185. /*if (Array.isArray(config.dependcss)) {
  186. configcss += config.dependcss
  187. .map(item => `<link rel="stylesheet" href=${item}?v=${Date.now()}>`)
  188. .join('');
  189. }*/
  190. Object.keys(entryMap).map((key) => {
  191. const cmodule = key.split("/")[0];
  192. // const buildInfo = getVersion('src/' + cmodule);
  193. const filePath = key.substr(0, key.length - 11);
  194. let configjs = getConfigJs(filePath); //额外配置的js文件
  195. let configcss = getConfigCss(filePath); //额外配置的css文件
  196. let htmlWebpackOption = {
  197. filename: `${key}.html`,
  198. template: path.join(projectPath, config['default-template']),
  199. chunks: [key],
  200. inject: true,
  201. templateParameters: {
  202. buildInfo: '',
  203. configjs: configjs, //为模板添加js
  204. configcss: configcss //为模板添加css
  205. }
  206. };
  207. if (entryTemplateMap[key]) {
  208. htmlWebpackOption.template = path.join(projectPath, entryTemplateMap[key]);
  209. }
  210. currentPlugin.push(new HtmlWebpackPlugin(htmlWebpackOption));
  211. });
  212. webpackProdConfig.entry = entryMap;
  213. webpackProdConfig.plugins = currentPlugin;
  214. Object.assign(webpackProdConfig.externals, externals);
  215. webpack(webpackProdConfig, (err, stats) => {
  216. console.log(stats.toString());
  217. if (err) {
  218. console.log(err);
  219. // throw new Error(err);
  220. reject();
  221. // return;
  222. }
  223. console.log(stats.toString({
  224. chunks: false, // Makes the build much quieter
  225. colors: true // Shows colors in the console
  226. }));
  227. let t = stats.endTime - stats.startTime;
  228. costTime.push(t);
  229. console.log('耗时:', t);
  230. resolve();
  231. });
  232. });
  233. }
  234. /*
  235. * 引用js优化,如果需要只在特定的html中引入uap的js,可以放开这里的代码
  236. * */
  237. function getConfigJs(filePath) {
  238. // dependjs: 依赖的js文件配置
  239. let configjs = '';
  240. if (config.dependjs && Array.isArray(config.dependjs[filePath])) {
  241. config.dependjs[filePath].forEach(file => {
  242. configjs += `<script src="${file}?v=${Date.now()}"></script>`;
  243. })
  244. }
  245. if (Array.isArray(config.report) && config.report.includes(filePath)) {
  246. configjs += `<script src="../../../../lappreportrt/nc-report/public/vendor.js"></script>`;
  247. configjs += `<script src="../../../../lappreportrt/nc-report/index.js"></script>`;
  248. }
  249. if (Array.isArray(config.wpsconfig) && config.wpsconfig.includes(filePath)) {
  250. configjs += `<script src="../../../../hrpub/public/wpsconfig/wps_sdk.js"></script>`;
  251. }
  252. return configjs;
  253. }
  254. function getConfigCss(filePath) {
  255. // dependcss: 依赖的css文件配置
  256. let configcss = '';
  257. if (Array.isArray(config.dependcss)) {
  258. configcss += config.dependcss
  259. .map(item => `<link rel="stylesheet" href=${item}?v=${Date.now()}>`)
  260. .join('');
  261. }
  262. if (Array.isArray(config.report) && config.report.includes(filePath)) {
  263. configcss += `<link rel="stylesheet" href="../../../../lappreportrt/nc-report/public/vendor.css" />`;
  264. configcss += `<link rel="stylesheet" href="../../../../lappreportrt/nc-report/index.css" />`;
  265. }
  266. return configcss;
  267. }