1/* 2 * Copyright (c) 2021 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16var path = require('path') 17var fs = require('fs') 18 19var ResourcePlugin = require('./lib/resource-plugin') 20var ResultStates = require('./lib/compile-plugin') 21var GenBinPlugin = require('./lib/genBin-plugin') 22var GenAbcPlugin = require('./lib/genAbc-plugin').GenAbcPlugin 23var AfterEmitPlugin = require('./lib/cardJson-plugin').AfterEmitPlugin 24const ReadJsonPlugin = require('./lib/read-json-plugin') 25 26const { PLATFORM }= require('./lib/lite/lite-enum') 27const util = require('./lib/util') 28const TerserPlugin = require('terser-webpack-plugin') 29const CopyPlugin = require("copy-webpack-plugin") 30const webpack = require('webpack') 31let watchMode = (process.env.watchMode && process.env.watchMode === 'true') || false 32const { 33 deleteFolderRecursive, 34 readManifest, 35 loadEntryObj, 36 hashProjectPath, 37 checkMultiResourceBuild, 38 readWorkerFile, 39 compareCache, 40 parseAbilityName 41} = require('./main.product') 42 43const richModule = { 44 rules: [ 45 { 46 test: /\.visual$/, 47 use: [{ 48 loader: path.resolve(__dirname, './lib/loader-gen.js') 49 }] 50 }, 51 { 52 test: /(\.hml)(\?[^?]+)?$/, 53 use: [{ 54 loader: path.resolve(__dirname, './index.js') 55 }] 56 }, 57 { 58 test: /\.png$/, 59 use: [{ 60 loader: 'file-loader', 61 options: { 62 name: '[name].[ext]', 63 outputPath: 'common' 64 } 65 }] 66 }, 67 { 68 test: /\.css$/, 69 use: [{ 70 loader: 'css-loader' 71 }] 72 }, 73 { 74 test: /\.less$/, 75 use: [{ 76 loader: 'less-loader' 77 }] 78 }, 79 { 80 test: /\.(scss|sass)$/, 81 use: [{ 82 loader: 'style-loader!css-loader!sass-loader' 83 }] 84 }, 85 { 86 test: /\.jsx?$/, 87 type: 'javascript/auto', 88 use: [ 89 { 90 loader: path.resolve(__dirname, 'lib/module-script.js') 91 }, 92 { 93 loader: util.loadBabelModule('babel-loader'), 94 options: { 95 presets: [util.loadBabelModule('@babel/preset-env')], 96 targets: 'node 8', 97 plugins: [util.loadBabelModule('@babel/plugin-transform-modules-commonjs'), 98 util.loadBabelModule('@babel/plugin-proposal-class-properties')], 99 compact: false 100 } 101 } 102 ] 103 } 104 ] 105} 106 107const cardModule = { 108 rules: [ 109 { 110 test: /\.visual$/, 111 use: [{ 112 loader: path.resolve(__dirname, './lib/loader-gen.js') 113 }] 114 }, 115 { 116 test: /\.hml$/, 117 use: [{ 118 loader: path.resolve(__dirname, './lib/card-loader.js') 119 }] 120 }, 121 { 122 test: /\.css$/, 123 use: [{ 124 loader: 'css-loader' 125 }] 126 }, 127 { 128 test: /\.less$/, 129 use: [{ 130 loader: 'less-loader' 131 }] 132 }, 133 { 134 test: /\.(scss|sass)$/, 135 use: [{ 136 loader: 'css-loader!sass-loader' 137 }] 138 }, 139 { 140 test: /\.jsx?$/, 141 type: 'javascript/auto', 142 use: [ 143 { 144 loader: path.resolve(__dirname, 'lib/module-script.js') 145 }, 146 { 147 loader: util.loadBabelModule('babel-loader'), 148 options: { 149 presets: [util.loadBabelModule('@babel/preset-env')], 150 targets: 'node 8', 151 plugins: [util.loadBabelModule('@babel/plugin-transform-modules-commonjs'), 152 util.loadBabelModule('@babel/plugin-proposal-class-properties')], 153 compact: false 154 } 155 } 156 ] 157 } 158 ] 159} 160 161let config = { 162 cache: { 163 type: 'filesystem' 164 }, 165 watch: watchMode, 166 watchOptions: { 167 aggregateTimeout: 10, 168 poll: false, 169 ignored: ["**/node_modules", "**/oh_modules", "**/*.json~"] 170 }, 171 172 output: { 173 filename: '[name].js', 174 devtoolModuleFilenameTemplate: 'webpack:///[absolute-resource-path]', 175 globalObject: 'globalThis' 176 }, 177 devtool: 'nosources-source-map', 178 mode: 'development', 179 module: richModule, 180 node: { 181 global: false 182 }, 183 stats: 'none' 184} 185 186function setConfigs(env) { 187 if (process.env.aceModuleJsonPath || env.aceModuleJsonPath) { 188 process.env.compileMode = 'moduleJson'; 189 } 190 process.env.error = env.error === undefined ? true : env.error 191 process.env.warning = env.warning === undefined ? true : env.warning 192 process.env.note = env.note === undefined ? true : env.note 193 process.env.buildMode = env.buildMode || 'debug' 194 process.env.logLevel = env.logLevel || '1' 195 process.env.isPreview = env.isPreview || false 196 process.env.projectPath = env.aceModuleRoot || process.env.aceModuleRoot || process.cwd(); 197 hashProjectPath(process.env.projectPath); 198 process.env.buildPath = env.aceModuleBuild || process.env.aceModuleBuild || 199 path.resolve(process.env.projectPath, 'build'); 200 process.env.cachePath = env.cachePath || process.env.cachePath || path.resolve(__dirname, 'node_modules/.cache'); 201 process.env.aceManifestPath = process.env.aceManifestPath || path.resolve(process.env.projectPath, 'manifest.json'); 202 process.env.abilityType = process.env.abilityType || 'page'; 203 process.env.DEVICE_LEVEL = env.DEVICE_LEVEL || process.env.DEVICE_LEVEL || 'rich'; 204 process.env.aceModuleJsonPath = env.aceModuleJsonPath || process.env.aceModuleJsonPath; 205 process.env.aceProfilePath = env.aceProfilePath || process.env.aceProfilePath; 206 process.env.watchCSSFiles = process.env.watchCSSFiles || path.resolve(process.env.cachePath, '.rich_cache', 'preview_css.json'); 207 watchMode = (process.env.watchMode && process.env.watchMode === 'true') || 208 (env.watchMode && env.watchMode === 'true') || false; 209 if (process.env.abilityType === 'page' || process.env.abilityType === 'form') { 210 const manifest = readManifest(process.env.aceManifestPath) 211 if (process.env.compileMode !== 'moduleJson') { 212 process.env.DEVICE_LEVEL = manifest.type === 'form' ? 'card' : 'rich' 213 } 214 process.env.PLATFORM_VERSION = PLATFORM.VERSION6; 215 const version = parseInt(manifest.minPlatformVersion); 216 if (version == 5) { 217 process.env.PLATFORM_VERSION = PLATFORM.VERSION5; 218 } 219 if (version <= 4) { 220 process.env.PLATFORM_VERSION = PLATFORM.VERSION3; 221 } 222 } 223 process.env.aceBuildJson = env.aceBuildJson || process.env.aceBuildJson; 224 checkMultiResourceBuild(process.env.aceBuildJson); 225} 226 227function setArkPlugin(env, workerFile) { 228 if (env.isPreview === "true" || env.compilerType && env.compilerType === 'ark') { 229 let arkDir = path.join(__dirname, 'bin', 'ark'); 230 if (env.arkFrontendDir) { 231 arkDir = env.arkFrontendDir; 232 } 233 let nodeJs = 'node'; 234 if (env.nodeJs) { 235 nodeJs = env.nodeJs; 236 } 237 config.plugins.push(new GenAbcPlugin(process.env.buildPath, arkDir, nodeJs, workerFile, 238 env.buildMode === 'debug')) 239 if (env.buildMode === 'release') { 240 config.output.path = path.join(process.env.cachePath, "releaseAssets", 241 path.basename(process.env.buildPath)); 242 process.env.configOutput = config.output.path; 243 } 244 } else { 245 if (env.deviceType) { 246 let deviceArr = env.deviceType.split(/,/) 247 let isDefault = deviceArr.indexOf('tv') >= 0 || deviceArr.indexOf('wearable') >= 0 ? true : false 248 if (isDefault) { 249 config.plugins.push(new GenBinPlugin(process.env.buildPath, path.join(__dirname, 'bin', workerFile))) 250 } 251 } 252 } 253} 254 255function existsPackageJson(config, rootPackageJsonPath, modulePackageJsonPath) { 256 if (config.cache) { 257 config.cache.buildDependencies = { 258 config: [] 259 }; 260 if (fs.existsSync(rootPackageJsonPath)) { 261 config.cache.buildDependencies.config.push(rootPackageJsonPath); 262 } 263 if (fs.existsSync(modulePackageJsonPath)) { 264 config.cache.buildDependencies.config.push(modulePackageJsonPath); 265 } 266 } 267} 268 269function excludeWorker(workerFile, name) { 270 if (workerFile) { 271 return Object.keys(workerFile).includes(name); 272 } 273 return /^\.\/workers\//.test(name); 274} 275 276module.exports = (env) => { 277 setConfigs(env); 278 compareCache(path.resolve(process.env.cachePath, '.rich_cache')); 279 const workerFile = readWorkerFile(); 280 if (process.env.compileMode === 'moduleJson') { 281 process.env.DEVICE_LEVEL = 'card'; 282 config.entry = {}; 283 } else { 284 deleteFolderRecursive(process.env.buildPath); 285 config.entry = loadEntryObj(process.env.projectPath, process.env.DEVICE_LEVEL, 286 process.env.abilityType, process.env.aceManifestPath); 287 existsPackageJson(config, path.resolve(process.env.projectPath, '../../../../../package.json'), 288 path.resolve(process.env.projectPath, '../../../../package.json')); 289 } 290 config.cache.cacheDirectory = path.resolve(process.env.cachePath, '.rich_cache', 291 path.basename(process.env.projectPath)); 292 config.output.path = path.resolve(__dirname, process.env.buildPath) 293 config.plugins = [ 294 new ResourcePlugin(process.env.projectPath, process.env.buildPath, 295 process.env.aceManifestPath, process.env.watchCSSFiles, workerFile), 296 new ResultStates({ 297 build: process.env.buildPath 298 }), 299 new webpack.DefinePlugin({ 300 STANDARD: JSON.stringify(true), 301 LITE: JSON.stringify(false) 302 }) 303 ] 304 config.resolve = { 305 modules: [ 306 process.env.projectPath, 307 path.join(process.env.projectPath, '../../../../../'), 308 path.join(__dirname, 'node_modules'), 309 './node_modules', 310 './oh_modules' 311 ], 312 descriptionFiles: ['package.json', 'oh-package.json5'], 313 plugins: [new ReadJsonPlugin()], 314 } 315 if (fs.existsSync(path.resolve(process.env.projectPath, 'i18n'))) { 316 config.plugins.push(new CopyPlugin({ 317 patterns: [ 318 { 319 from: path.resolve(process.env.projectPath, 'i18n'), 320 to: path.resolve(process.env.buildPath, 'i18n'), 321 noErrorOnMissing: true 322 } 323 ] 324 })) 325 } 326 if (process.env.aceConfigPath && fs.existsSync(process.env.aceConfigPath)) { 327 config.plugins.push(new CopyPlugin({ 328 patterns: [ 329 { 330 from: path.resolve(process.env.aceConfigPath), 331 to: path.resolve(process.env.buildPath, 'config.json'), 332 noErrorOnMissing: true 333 } 334 ] 335 })) 336 } 337 if (process.env.DEVICE_LEVEL === 'card') { 338 config.module = cardModule 339 config.plugins.push(new AfterEmitPlugin()) 340 setArkPlugin(env, workerFile); 341 } else { 342 if (process.env.compileMode !== 'moduleJson' && process.env.abilityType === 'page') { 343 config.optimization = { 344 splitChunks: { 345 chunks(chunk) { 346 return !excludeWorker(workerFile, chunk.name) && !/^\.\/TestAbility/.test(chunk.name); 347 }, 348 minSize: 0, 349 cacheGroups: { 350 vendors: { 351 test: /[\\/](node|oh)_modules[\\/]/, 352 priority: 20, 353 name: "vendors", 354 }, 355 commons: { 356 test: /\.js|css|hml$/, 357 name: 'commons', 358 priority: 10, 359 minChunks: 2, 360 } 361 } 362 }, 363 } 364 } 365 setArkPlugin(env, workerFile); 366 if (env.sourceMap === 'none') { 367 config.devtool = false 368 } 369 if (env.buildMode === 'release') { 370 config.mode = 'production' 371 if (process.env.compileMode !== 'moduleJson' && process.env.abilityType === 'page') { 372 config.optimization = config.optimization; 373 } else { 374 config.optimization = {}; 375 } 376 Object.assign(config.optimization, { 377 minimize: true, 378 minimizer: [new TerserPlugin({ 379 terserOptions: { 380 compress: { 381 defaults: false, 382 dead_code: true, 383 collapse_vars: true, 384 unused: true, 385 drop_debugger: true, 386 if_return: true, 387 reduce_vars: true, 388 join_vars: false, 389 sequences: 0 390 }, 391 format: { 392 semicolons: false, 393 beautify: true, 394 braces: true, 395 indent_level: 2 396 } 397 } 398 })] 399 }) 400 config.output.devtoolModuleFilenameTemplate = (info) => { 401 return `webpack:///${info.absoluteResourcePath.replace(process.env.projectRootPath, '')}`; 402 } 403 config.output.sourceMapFilename = '_releaseMap/[name].js.map' 404 } 405 } 406 if (process.env.abilityType === 'testrunner') { 407 config.module.rules = []; 408 config.module.rules.unshift({ 409 test: /TestRunner/, 410 use: [{ 411 loader: path.resolve(__dirname, './index.js') 412 }] 413 }) 414 } else { 415 config.module.rules.unshift({ 416 test: parseAbilityName(process.env.abilityType, process.env.projectPath), 417 use: [{ 418 loader: path.resolve(__dirname, './index.js') 419 }] 420 }) 421 } 422 423 config.output.library = process.env.hashProjectPath; 424 return config 425} 426