Files
react-native-devtools-frontend/scripts/check_gn.js
T
Tim van der Lippe 8bdbc7af8c Use rollup to bundle module entrypoints
Settting the Ninja arg `is_debug` will retain the old behavior. However,
setting that flag to `false` will start using Rollup. Rollup will bundle
everything into an entrypoint, but will avoid bundling module
dependencies.

For example, if a file in `ui` depends on `common`, then everything in
`ui` will be bundled into `ui/ui.js`. But, it will retain all imports to
`common` as `import * as Common from '../common/common.js';`.

This also caught an issue with misconfiguration in the
wasmparser_worker, which should import the files directly and can't use
it in the dependencies array of the module.json

Lastly, the BUILD.gn definition is significantly cleaned up. In the
process of doing all this work, I discovered that we can simply use
`foreach` to iterate through all source files. This removes the
duplication of both `fron_end` and `$resources_out_dir` and
significantly reduces the amount of clutter in BUILD.gn.

As such, update check-gn.js to check for the correct GN variables.

roll CodeMirror: ignore

Bug: 1046596
Change-Id: I7dcda7949e79e001c8a11307dc902f96a8fa6696
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2089906
Commit-Queue: Tim van der Lippe <tvanderlippe@chromium.org>
Reviewed-by: Jack Franklin <jacktfranklin@chromium.org>
2020-03-09 10:59:37 +00:00

178 lines
6.0 KiB
JavaScript

// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
'use strict';
const fs = require('fs');
const path = require('path');
const FRONTEND_PATH = path.resolve(__dirname, '..', 'front_end');
const manifestModules = [];
for (var config of ['inspector.json', 'devtools_app.json', 'js_app.json', 'node_app.json', 'shell.json', 'worker_app.json'])
manifestModules.push(...require(path.resolve(FRONTEND_PATH, config)).modules);
const utils = require('./utils');
const gnPath = path.resolve(__dirname, '..', 'BUILD.gn');
const gnFile = fs.readFileSync(gnPath, 'utf-8');
const gnLines = gnFile.split('\n');
function main() {
let errors = [
...checkNonAutostartNonRemoteModules(),
...checkAllDevToolsFiles(),
...checkAllDevToolsModules(),
...checkDevtoolsModuleEntrypoints(),
];
if (errors.length) {
console.log('DevTools BUILD.gn checker detected errors!');
console.log(`There's an issue with: ${gnPath}`);
console.log(errors.join('\n'));
process.exit(1);
}
console.log('DevTools BUILD.gn checker passed');
}
main();
/**
* Ensures that generated module files are in the right list in BUILD.gn.
* This is primarily to avoid remote modules from accidentally getting
* bundled with the main Chrome binary.
*/
function checkNonAutostartNonRemoteModules() {
const errors = [];
const gnVariable = 'generated_non_autostart_non_remote_modules';
const lines = selectGNLines(`${gnVariable} = [`, ']');
if (!lines.length) {
return [
'Could not identify non-autostart non-remote modules in gn file',
'Please look at: ' + __filename,
];
}
const text = lines.join('\n');
const modules = manifestModules.filter(m => m.type !== 'autostart' && m.type !== 'remote').map(m => m.name);
const missingModules = modules.filter(m => !utils.includes(text, `${m}/${m}_module.js`));
if (missingModules.length)
errors.push(`Check that you've included [${missingModules.join(', ')}] modules in: ` + gnVariable);
// e.g. "$resources_out_dir/lighthouse/lighthouse_module.js" => "lighthouse"
const mapLineToModuleName = line => line.split('/')[2].split('_module')[0];
const extraneousModules = lines.map(mapLineToModuleName).filter(module => !utils.includes(modules, module));
if (extraneousModules.length)
errors.push(`Found extraneous modules [${extraneousModules.join(', ')}] in: ` + gnVariable);
return errors;
}
/**
* Ensures that all source files (according to the various module.json files) are
* listed in BUILD.gn.
*/
function checkAllDevToolsFiles() {
return checkGNVariable('all_devtools_files', (moduleJSON) => {
const scripts = moduleJSON.scripts || [];
const resources = moduleJSON.resources || [];
return [
'module.json',
...scripts,
...resources,
];
});
}
function checkAllDevToolsModules() {
return checkGNVariable(
'all_devtools_modules',
(moduleJSON, folderName) => {
return (moduleJSON.modules || []).filter(fileName => {
return fileName !== `${folderName}.js` && fileName !== `${folderName}-legacy.js`;
});
},
(buildGNPath) => (filename) => {
const relativePath = path.normalize(`${buildGNPath}/${filename}`);
return `"${relativePath}",`;
});
}
function checkDevtoolsModuleEntrypoints() {
return checkGNVariable(
'devtools_module_entrypoints',
(moduleJSON, folderName) => {
return (moduleJSON.modules || []).filter(fileName => {
return fileName === `${folderName}.js` || fileName === `${folderName}-legacy.js`;
});
},
(buildGNPath) => (filename) => {
const relativePath = path.normalize(`${buildGNPath}/${filename}`);
return `"${relativePath}",`;
});
}
function checkGNVariable(gnVariable, obtainFiles, obtainRelativePath) {
const errors = [];
const excludedFiles = ['axe.js', 'formatter_worker/', 'third_party/lighthouse/'].map(path.normalize);
const lines = selectGNLines(`${gnVariable} = [`, ']').map(path.normalize);
if (!lines.length) {
return [
`Could not identify ${gnVariable} list in gn file`,
'Please look at: ' + __filename,
];
}
const gnFiles = new Set(lines);
var moduleFiles = [];
function addModuleFilesForDirectory(moduleJSONPath, buildGNPath, folderName) {
const moduleJSON = require(moduleJSONPath);
const files = obtainFiles(moduleJSON, folderName)
.map(obtainRelativePath && obtainRelativePath(buildGNPath) || relativePathFromBuildGN)
.filter(file => excludedFiles.every(excludedFile => !file.includes(excludedFile)));
moduleFiles = moduleFiles.concat(files);
function relativePathFromBuildGN(filename) {
const relativePath = path.normalize(`front_end/${buildGNPath}/${filename}`);
return `"${relativePath}",`;
}
}
function traverseDirectoriesForModuleJSONFiles(folderName, buildGNPath) {
if (!fs.lstatSync(folderName).isDirectory()) {
return;
}
const moduleJSONPath = path.join(folderName, 'module.json');
if (utils.isFile(moduleJSONPath)) {
addModuleFilesForDirectory(moduleJSONPath, buildGNPath, path.basename(folderName));
}
fs.readdirSync(folderName).forEach((nestedModuleName) => {
traverseDirectoriesForModuleJSONFiles(
path.join(folderName, nestedModuleName), `${buildGNPath}/${nestedModuleName}`);
});
}
fs.readdirSync(FRONTEND_PATH).forEach((moduleName) => {
traverseDirectoriesForModuleJSONFiles(path.join(FRONTEND_PATH, moduleName), moduleName);
});
for (const file of moduleFiles) {
if (!gnFiles.has(file))
errors.push(`Missing file in BUILD.gn for ${gnVariable}: ` + file);
}
return errors;
}
function selectGNLines(startLine, endLine) {
let lines = gnLines.map(line => line.trim());
let startIndex = lines.indexOf(startLine);
if (startIndex === -1)
return [];
let endIndex = lines.indexOf(endLine, startIndex);
if (endIndex === -1)
return [];
return lines.slice(startIndex + 1, endIndex);
}