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