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