• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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