Add webpack bundling for the extension (#1308)

* Add webpack bundling for the extension
* Fix dependencies problem
* Change build script
* Add webpack-bundle-analyzer
* Add localization pipeline to bundling scenario
* Update localization configs to suit vscode-nls@4
* Added localization smoke test
* Resolve webpack dynamic require problem, add additional attribution
This commit is contained in:
Yuri Skorokhodov 2020-06-10 00:20:02 +03:00 коммит произвёл GitHub
Родитель 9442a7e6d7
Коммит 2d8af44863
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
41 изменённых файлов: 3246 добавлений и 77 удалений

Просмотреть файл

@ -10,8 +10,8 @@ steps:
- bash: npm ci
displayName: 'npm ci'
- bash: npm run vscode:prepublish
displayName: 'npm run vscode:prepublish'
- bash: npm run build
displayName: 'npm run build'
- bash: |
/usr/bin/Xvfb :99 -screen 0 1024x768x24 > /dev/null 2>&1 &

Просмотреть файл

@ -33,6 +33,7 @@ steps:
displayName: 'gulp release'
inputs:
targets: release
arguments: --nightly
- task: CopyFiles@2
displayName: 'Copy Files to: test/smoke/package/resources/drop-win'

1
.gitignore поставляемый
Просмотреть файл

@ -11,6 +11,7 @@ test/resources/projects/*
# Compiled files
src/**/*.js
dist/**
!src/extension/appcenter/lib/**/*.js
test/**/*.js
test/smoke/vscode

Просмотреть файл

@ -6,8 +6,11 @@
test/**
out/**
src/**
!src/**/*.js
.ci/**
dist/src
node_modules/**
**/*.js.map
i18n/**
SampleApplication/**
tools/**
.vscodeignore

Просмотреть файл

@ -20,20 +20,24 @@ const remapIstanbul = require("remap-istanbul/lib/gulpRemapIstanbul");
const nls = require("vscode-nls-dev");
const libtslint = require("tslint");
const tslint = require("gulp-tslint");
const webpack = require("webpack");
const filter = require('gulp-filter');
const del = require("del");
const vscodeTest = require("vscode-test");
const copyright = GulpExtras.checkCopyright;
const imports = GulpExtras.checkImports;
const executeCommand = GulpExtras.executeCommand;
const tsProject = ts.createProject("tsconfig.json");
/**
* Whether we're running a nightly build.
*/
const isNightly = process.argv.includes('--nightly');
const isNightly = process.argv.includes("--nightly");
const ExtensionName = isNightly ? "msjsdiag.vscode-react-native-preview" : "msjsdiag.vscode-react-native";
const translationProjectName = "vscode-extensions";
const translationExtensionName = "vscode-react-native";
const defaultLanguages = [
{ id: "zh-tw", folderName: "cht", transifexId: "zh-hant" },
{ id: "zh-cn", folderName: "chs", transifexId: "zh-hans" },
@ -54,6 +58,9 @@ const defaultLanguages = [
const srcPath = "src";
const testPath = "test";
const buildDir = "src";
const distDir = "dist";
const distSrcDir = `${distDir}/src`;
const sources = [srcPath, testPath].map((tsFolder) => tsFolder + "/**/*.ts");
@ -72,8 +79,106 @@ lintSources = lintSources.concat([
"!/SmokeTestLogs/**"
]);
async function runWebpack({
packages = [],
devtool = false,
compileInPlace = false,
mode = process.argv.includes("watch") ? "development" : "production",
} = options) {
let configs = [];
for (const { entry, library, filename } of packages) {
const config = {
mode,
target: "node",
entry: path.resolve(entry),
output: {
path: compileInPlace ? path.resolve(path.dirname(entry)) : path.resolve(distDir),
filename: filename || path.basename(entry).replace(".js", ".bundle.js"),
devtoolModuleFilenameTemplate: "../[resource-path]",
},
devtool: devtool,
resolve: {
extensions: [".js", ".ts", ".json"],
},
module: {
rules: [{
test: /\.ts$/,
exclude: /node_modules/,
use: [{
// vscode-nls-dev loader:
// * rewrite nls-calls
loader: 'vscode-nls-dev/lib/webpack-loader',
options: {
base: path.join(__dirname)
}
}, {
// configure TypeScript loader:
// * enable sources maps for end-to-end source maps
loader: 'ts-loader',
options: {
compilerOptions: {
"sourceMap": true,
}
}
}]
}]
},
node: {
__dirname: false,
__filename: false,
},
externals: {
vscode: "commonjs vscode",
}
};
if (library) {
config.output.libraryTarget = "commonjs2";
}
if (process.argv.includes("--analyze-size")) {
config.plugins = [
new (require("webpack-bundle-analyzer").BundleAnalyzerPlugin)({
analyzerMode: "static",
reportFilename: path.resolve(distSrcDir, path.basename(entry) + ".html"),
}),
];
}
configs.push(config);
}
await new Promise((resolve, reject) =>
webpack(configs, (err, stats) => {
if (err) {
reject(err);
} else if (stats.hasErrors()) {
reject(stats);
} else {
resolve();
}
}),
);
}
// Generates ./dist/nls.bundle.<language_id>.json from files in ./i18n/** *//<src_path>/<filename>.i18n.json
// Localized strings are read from these files at runtime.
const generateSrcLocBundle = () => {
// Transpile the TS to JS, and let vscode-nls-dev scan the files for calls to localize.
return tsProject.src()
.pipe(sourcemaps.init())
.pipe(tsProject()).js
.pipe(nls.createMetaDataFiles())
.pipe(nls.createAdditionalLanguageFiles(defaultLanguages, "i18n"))
.pipe(nls.bundleMetaDataFiles(ExtensionName, 'dist'))
.pipe(nls.bundleLanguageFiles())
.pipe(filter(['**/nls.bundle.*.json', '**/nls.metadata.header.json', '**/nls.metadata.json', "!src/**"]))
.pipe(gulp.dest('dist'));
};
function build(failOnError, buildNls) {
const tsProject = ts.createProject("tsconfig.json");
const isProd = options.env === "production";
const preprocessorContext = isProd ? { PROD: true } : { DEBUG: true };
let gotError = false;
@ -86,7 +191,7 @@ function build(failOnError, buildNls) {
return tsResult.js
.pipe(buildNls ? nls.rewriteLocalizeCalls() : es.through())
.pipe(buildNls ? nls.createAdditionalLanguageFiles(defaultLanguages, "i18n", ".") : es.through())
.pipe(buildNls ? nls.bundleMetaDataFiles("msjsdiag.vscode-react-native", ".") : es.through())
.pipe(buildNls ? nls.bundleMetaDataFiles(ExtensionName, ".") : es.through())
.pipe(buildNls ? nls.bundleLanguageFiles() : es.through())
.pipe(sourcemaps.write(".", { includeContent: false, sourceRoot: "." }))
.pipe(gulp.dest((file) => file.cwd))
@ -106,7 +211,7 @@ async function test() {
if (options.pattern) {
log(`\nTesting cases that match pattern: ${options.pattern}`);
} else {
log("\nTesting cases that don't match pattern: extensionContext|localizationContext");
log(`\nTesting cases that don't match pattern: extensionContext|localizationContext`);
}
try {
@ -149,7 +254,8 @@ gulp.task("check-copyright", () => {
"!test/smoke/package/node_modules/**",
"!test/smoke/automation/node_modules/**",
"!test/smoke/resources/**",
"!test/smoke/vscode/**"
"!test/smoke/vscode/**",
"!dist/**"
])
.pipe(copyright());
});
@ -164,10 +270,36 @@ gulp.task("tslint", () => {
.pipe(tslint.report());
});
/** Run webpack to bundle the extension output files */
gulp.task("webpack-bundle", async () => {
const packages = [
{ entry: `${buildDir}/extension/rn-extension.ts`, filename: "rn-extension.js", library: true },
];
return runWebpack({ packages });
});
gulp.task("clean", () => {
const pathsToDelete = [
"src/**/*.js",
"src/**/*.js.map",
"test/**/*.js",
"test/**/*.js.map",
"out/",
"dist",
"!test/resources/sampleReactNative022Project/**/*.js",
".vscode-test/",
"nls.*.json",
"!test/smoke/**/*.js",
"!test/smoke/**/*.js.map",
]
return del(pathsToDelete, { force: true });
});
// TODO: The file property should point to the generated source (this implementation adds an extra folder to the path)
// We should also make sure that we always generate urls in all the path properties (We shouldn"t have \\s. This seems to
// be an issue on Windows platforms)
gulp.task("build", gulp.series("check-imports", "check-copyright", "tslint", function runBuild(done) {
gulp.task("build", gulp.series("clean", "check-imports", "check-copyright", "tslint", function runBuild(done) {
build(true, true)
.once("finish", () => {
done();
@ -188,24 +320,9 @@ gulp.task("watch", gulp.series("build", function runWatch() {
return gulp.watch(sources, gulp.series("build"));
}));
gulp.task("clean", () => {
const del = require("del");
const pathsToDelete = [
"src/**/*.js",
"src/**/*.js.map",
"test/**/*.js",
"test/**/*.js.map",
"out/",
"!test/resources/sampleReactNative022Project/**/*.js",
".vscode-test/",
"nls.*.json",
"!test/smoke/**/*.js",
"!test/smoke/**/*.js.map",
]
return del(pathsToDelete, { force: true });
});
gulp.task("prod-build", gulp.series("clean", "webpack-bundle", generateSrcLocBundle));
gulp.task("default", gulp.series("clean", "build"));
gulp.task("default", gulp.series("prod-build"));
gulp.task("test", gulp.series("build", "tslint", test));
@ -255,7 +372,7 @@ gulp.task("package", (callback) => {
});
function readJson(file) {
const contents = fs.readFileSync(path.join(__dirname, file), 'utf-8').toString();
const contents = fs.readFileSync(path.join(__dirname, file), "utf-8").toString();
return JSON.parse(contents);
}
@ -264,8 +381,11 @@ function writeJson(file, jsonObj) {
fs.writeFileSync(path.join(__dirname, file), content);
}
/**
* Generate version number for a nightly build.
*/
const getVersionNumber = () => {
const date = new Date(new Date().toLocaleString('en-US', { timeZone: 'America/Los_Angeles' }));
const date = new Date(new Date().toLocaleString("en-US", { timeZone: "America/Los_Angeles" }));
return [
// YY
@ -273,22 +393,23 @@ const getVersionNumber = () => {
// MM,
date.getMonth() + 1,
//DDHH
`${date.getDate()}${String(date.getHours()).padStart(2, '0')}`,
].join('.');
`${date.getDate()}${String(date.getHours()).padStart(2, "0")}`,
].join(".");
};
gulp.task("release", gulp.series("build", function prepareLicenses() {
const licenseFiles = ["LICENSE.txt", "ThirdPartyNotices.txt"];
gulp.task("release", function prepareLicenses() {
const backupFiles = ["LICENSE.txt", "ThirdPartyNotices.txt", "package.json"];
const backupFolder = path.resolve(path.join(os.tmpdir(), "vscode-react-native"));
if (!fs.existsSync(backupFolder)) {
fs.mkdirSync(backupFolder);
}
return Q({})
.then(() => {
/* back up LICENSE.txt, ThirdPartyNotices.txt, README.md */
log("Backing up license files to " + backupFolder + "...");
licenseFiles.forEach((fileName) => {
backupFiles.forEach((fileName) => {
fs.writeFileSync(path.join(backupFolder, fileName), fs.readFileSync(fileName));
});
@ -297,12 +418,13 @@ gulp.task("release", gulp.series("build", function prepareLicenses() {
fs.writeFileSync("LICENSE.txt", fs.readFileSync("release/LICENSE.txt"));
fs.writeFileSync("ThirdPartyNotices.txt", fs.readFileSync("release/ThirdPartyNotices.txt"));
}).then(() => {
let packageJson = readJson("package.json");
packageJson.main = "./dist/rn-extension";
if (isNightly) {
log("Performing nightly release...");
let packageJson = readJson("package.json");
packageJson.version = getVersionNumber();
writeJson("package.json", packageJson);
}
writeJson("package.json", packageJson);
log("Creating release package...");
var deferred = Q.defer();
// NOTE: vsce must see npm 3.X otherwise it will not correctly strip out dev dependencies.
@ -311,11 +433,11 @@ gulp.task("release", gulp.series("build", function prepareLicenses() {
}).finally(() => {
/* restore backed up files */
log("Restoring modified files...");
licenseFiles.forEach((fileName) => {
backupFiles.forEach((fileName) => {
fs.writeFileSync(path.join(__dirname, fileName), fs.readFileSync(path.join(backupFolder, fileName)));
});
});
}));
});
// Creates package.i18n.json files for all languages from {workspaceRoot}/i18n folder into project root
gulp.task("add-i18n", () => {
@ -327,7 +449,7 @@ gulp.task("add-i18n", () => {
// Creates MLCP readable .xliff file and saves it locally
gulp.task("translations-export", gulp.series("build", function runTranslationExport() {
return gulp.src(["package.nls.json", "nls.metadata.header.json", "nls.metadata.json"])
.pipe(nls.createXlfFiles(translationProjectName, translationExtensionName))
.pipe(nls.createXlfFiles(translationProjectName, ExtensionName))
.pipe(gulp.dest(path.join("..", `${translationProjectName}-localization-export`)));
}));
@ -341,8 +463,8 @@ gulp.task("translations-import", (done) => {
});
es.merge(defaultLanguages.map((language) => {
let id = language.transifexId || language.id;
log(path.join(options.location, id, 'vscode-extensions', `${translationExtensionName}.xlf`));
return gulp.src(path.join(options.location, id, 'vscode-extensions', `${translationExtensionName}.xlf`))
log(path.join(options.location, id, "vscode-extensions", `${ExtensionName}.xlf`));
return gulp.src(path.join(options.location, id, "vscode-extensions", `${ExtensionName}.xlf`))
.pipe(nls.prepareJsonFiles())
.pipe(gulp.dest(path.join("./i18n", language.folderName)));
}))

2915
package-lock.json сгенерированный

Разница между файлами не показана из-за своего большого размера Загрузить разницу

Просмотреть файл

@ -670,8 +670,7 @@
}
},
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"compile": "node ./node_modules/vscode/bin/compile -watch -p ./",
"build": "gulp build",
"vscode:prepublish": "gulp",
"test": "node ./test/runTest.js",
"test-localization": "node ./test/localization/runTest.js",
@ -694,7 +693,7 @@
"vscode-cdp-proxy": "^0.2.0",
"vscode-debugadapter": "^1.39.1",
"vscode-extension-telemetry": "0.0.5",
"vscode-nls": "3.2.2",
"vscode-nls": "^4.1.2",
"ws": "^7.3.0"
},
"devDependencies": {
@ -713,11 +712,13 @@
"@types/websocket": "0.0.33",
"@types/ws": "^0.0.39",
"ansi-colors": "^3.2.4",
"copy-webpack-plugin": "^6.0.2",
"del": "^2.2.0",
"devtools-protocol": "0.0.762508",
"event-stream": "3.3.4",
"fancy-log": "^1.3.3",
"gulp": "^4.0.2",
"gulp-filter": "^6.0.0",
"gulp-istanbul": "^1.1.3",
"gulp-mocha": "^7.0.2",
"gulp-preprocess": "^3.0.3",
@ -737,12 +738,15 @@
"sinon": "^1.17.3",
"source-map-support": "^0.4.0",
"through2": "^2.0.1",
"ts-loader": "^7.0.5",
"tslint": "^5.20.1",
"typescript": "^3.7.5",
"vsce": "^1.74.0",
"vscode-debugprotocol": "^1.40.0",
"vscode-nls-dev": "^3.3.1",
"vscode-test": "^1.3.0"
"vscode-test": "^1.3.0",
"webpack": "^4.43.0",
"webpack-bundle-analyzer": "^3.8.0"
},
"extensionDependencies": [
"ms-vscode.js-debug-nightly"

Просмотреть файл

@ -2,6 +2,7 @@
2. TACO Tools for Apache Cordova (https://github.com/Microsoft/TACO)
3. React Native command line tools (https://github.com/react-native-community/react-native-cli)
4. Expo XDL (https://github.com/expo/expo-cli/tree/master/packages/xdl)
5. OW (https://github.com/sindresorhus/ow)
%% DefinitelyTyped NOTICES, INFORMATION, AND LICENSE BEGIN HERE
@ -123,3 +124,17 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
=========================================
END OF Expo XDL NOTICES, INFORMATION, AND LICENSE
%% ow NOTICES, INFORMATION, AND LICENSE BEGIN HERE
=========================================
MIT License
Copyright (c) Sindre Sorhus <sindresorhus@gmail.com> (https://sindresorhus.com)
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
=========================================
END OF ow NOTICES, INFORMATION, AND LICENSE

Просмотреть файл

@ -13,6 +13,7 @@ import {HostPlatform, HostPlatformId} from "./hostPlatform";
import {ErrorHelper} from "./error/errorHelper";
import {InternalErrorCode} from "./error/internalErrorCode";
import * as nls from "vscode-nls";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
export enum CommandVerbosity {

Просмотреть файл

@ -0,0 +1,17 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
// Portion of code was taken from https://github.com/sindresorhus/ow/blob/d62a06c192b892d504887f0b97fdc842e8cbf862/source/utils/node/require.ts
let customRequire: (packageName: string) => any;
try {
// Export `__non_webpack_require__` in Webpack environments to make sure it doesn't bundle modules loaded via this method
customRequire = (global as any).__non_webpack_require__ === "function"
? (global as any).__non_webpack_require__
: eval("require"); // tslint:disable-line:no-eval
} catch {
// Use a noop in case both `__non_webpack_require__` and `require` does not exist
customRequire = () => {}; // tslint:disable-line:no-empty
}
export default customRequire;

Просмотреть файл

@ -2,6 +2,7 @@
// Licensed under the MIT license. See LICENSE file in the project root for details.
import * as nls from "vscode-nls";
import {InternalErrorCode} from "./internalErrorCode";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
export const ERROR_STRINGS = {

Просмотреть файл

@ -5,8 +5,37 @@ import * as path from "path";
import * as fs from "fs";
export function getExtensionVersion() {
const projectRoot = path.join(__dirname, "..", "..");
return JSON.parse(fs.readFileSync(path.join(projectRoot, "package.json"), "utf-8")).version;
const packageJsonPath = findFileInFolderHierarchy(__dirname, "package.json");
if (packageJsonPath) {
return JSON.parse(fs.readFileSync(packageJsonPath, "utf-8")).version;
} else {
return null;
}
}
export function findFileInFolderHierarchy(dir: string, filename: string): string | null {
let parentPath: string;
let projectRoot: string = dir;
let atFsRoot: boolean = false;
while (!fs.existsSync(path.join(projectRoot, filename))) {
// Navigate up one level until either config.xml is found
parentPath = path.resolve(projectRoot, "..");
if (parentPath !== projectRoot) {
projectRoot = parentPath;
} else {
// we have reached the filesystem root
atFsRoot = true;
break;
}
}
if (atFsRoot) {
// We reached the fs root
return null;
}
return path.join(projectRoot, filename);
}
export function generateRandomPortNumber() {

Просмотреть файл

@ -22,6 +22,8 @@ import * as XDL from "../extension/exponent/xdlInterface";
import * as semver from "semver";
import { FileSystem } from "./node/fileSystem";
import * as nls from "vscode-nls";
import { findFileInFolderHierarchy } from "./extensionHelper";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
export class Packager {
@ -37,7 +39,7 @@ export class Packager {
old: "opn-main.js",
};
private static RN_VERSION_WITH_OPEN_PKG = "0.60.0";
private static JS_INJECTOR_DIRPATH = path.resolve(path.dirname(path.dirname(__dirname)), "js-patched");
private static JS_INJECTOR_DIRPATH = findFileInFolderHierarchy(__dirname, "js-patched") || __dirname;
private static NODE_MODULES_FODLER_NAME = "node_modules";
private static OPN_PACKAGE_NAME = {
new: "open",

Просмотреть файл

@ -28,11 +28,12 @@ export class ReactNativeProjectHelper {
}
public static isHaulProject(projectRoot: string): boolean {
if (!projectRoot || !fs.existsSync(path.join(projectRoot, "package.json"))) {
const packageJsonPath = path.join(projectRoot, "package.json");
if (!projectRoot || !fs.existsSync(packageJsonPath)) {
return false;
}
const packageJson = require(path.join(projectRoot, "package.json"));
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf-8"));
const haulVersion = packageJson.devDependencies && (packageJson.devDependencies.haul || packageJson.devDependencies["@haul-bundler/cli"]);
return !!haulVersion;
}

Просмотреть файл

@ -15,6 +15,7 @@ import { ScriptImporter } from "./scriptImporter";
import { ReactNativeProjectHelper } from "../common/reactNativeProjectHelper";
import * as nls from "vscode-nls";
import { InternalErrorCode } from "../common/error/internalErrorCode";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
export interface RNAppMessage {

Просмотреть файл

@ -17,6 +17,7 @@ import { ILaunchArgs } from "../extension/launchArgs";
import { AppLauncher } from "../extension/appLauncher";
import { LogLevel } from "../extension/log/LogHelper";
import * as nls from "vscode-nls";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
/**

Просмотреть файл

@ -11,6 +11,7 @@ import { DebugSessionBase, IAttachRequestArgs, ILaunchRequestArgs } from "../deb
import { JsDebugConfigAdapter } from "../jsDebugConfigAdapter";
import { DebuggerEndpointHelper } from "../../cdp-proxy/debuggerEndpointHelper";
import * as nls from "vscode-nls";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
export class DirectDebugSession extends DebugSessionBase {

Просмотреть файл

@ -13,6 +13,7 @@ import { RnCDPMessageHandler } from "../cdp-proxy/CDPMessageHandlers/rnCDPMessag
import { DebugSessionBase, DebugSessionStatus, IAttachRequestArgs, ILaunchRequestArgs } from "./debugSessionBase";
import { JsDebugConfigAdapter } from "./jsDebugConfigAdapter";
import * as nls from "vscode-nls";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
export class RNDebugSession extends DebugSessionBase {

Просмотреть файл

@ -10,6 +10,7 @@ import * as fs from "fs";
import { ILogger } from "../log/LogHelper";
import * as os from "os";
import * as nls from "vscode-nls";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
// See android versions usage at: http://developer.android.com/about/dashboards/index.html

Просмотреть файл

@ -18,6 +18,7 @@ import * as nls from "vscode-nls";
import { InternalErrorCode } from "../../common/error/internalErrorCode";
import { ErrorHelper } from "../../common/error/errorHelper";
import { isNullOrUndefined } from "util";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
/**

Просмотреть файл

@ -9,6 +9,7 @@ import { OutputChannelLogger } from "../log/OutputChannelLogger";
import { ExecutionsFilterBeforeTimestamp } from "../../common/executionsLimiter";
import { AdbHelper } from "./adb";
import * as nls from "vscode-nls";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
/* This class will print the LogCat messages to an Output Channel. The configuration for logcat can be cutomized in

Просмотреть файл

@ -25,6 +25,7 @@ import {ReactNativeCDPProxy} from "../cdp-proxy/reactNativeCDPProxy";
import {generateRandomPortNumber} from "../common/extensionHelper";
import * as nls from "vscode-nls";
import { MultipleLifetimesAppWorker } from "../debugger/appWorker";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
export class AppLauncher {

Просмотреть файл

@ -23,6 +23,7 @@ import * as nls from "vscode-nls";
import {ErrorHelper} from "../common/error/errorHelper";
import {InternalErrorCode} from "../common/error/internalErrorCode";
import {AppLauncher} from "./appLauncher";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
export class CommandPaletteHandler {

Просмотреть файл

@ -5,6 +5,7 @@ import * as vscode from "vscode";
import { TelemetryHelper } from "../common/telemetryHelper";
import { Telemetry } from "../common/telemetry";
import * as nls from "vscode-nls";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
export const DEBUG_TYPES = {

Просмотреть файл

@ -14,6 +14,7 @@ import stripJSONComments = require("strip-json-comments");
import * as nls from "vscode-nls";
import { ErrorHelper } from "../../common/error/errorHelper";
import { InternalErrorCode } from "../../common/error/internalErrorCode";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
const APP_JSON = "app.json";

Просмотреть файл

@ -14,6 +14,7 @@ import * as Q from "q";
import * as XDL from "./xdlInterface";
import * as url from "url";
import * as nls from "vscode-nls";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();

Просмотреть файл

@ -8,6 +8,8 @@ import {OutputChannelLogger} from "../log/OutputChannelLogger";
import * as XDLPackage from "xdl";
import * as path from "path";
import * as Q from "q";
import { findFileInFolderHierarchy } from "../../common/extensionHelper";
import customRequire from "../../common/customRequire";
const logger: OutputChannelLogger = OutputChannelLogger.getMainChannel();
@ -26,7 +28,7 @@ function getPackage(): Q.Promise<typeof XDLPackage> {
// Don't do the require if we don't actually need it
try {
logger.debug("Getting exponent dependency.");
const xdl = require(XDL_PACKAGE);
const xdl = customRequire(XDL_PACKAGE);
xdlPackage = Q(xdl);
return xdlPackage;
} catch (e) {
@ -36,12 +38,12 @@ function getPackage(): Q.Promise<typeof XDLPackage> {
throw e;
}
}
let commandExecutor = new CommandExecutor(path.dirname(require.resolve("../../../")), logger);
let commandExecutor = new CommandExecutor(path.dirname(findFileInFolderHierarchy(__dirname, "package.json") || __dirname), logger);
xdlPackage = commandExecutor.spawnWithProgress(HostPlatform.getNpmCliCommand("npm"),
["install", ...EXPO_DEPS, "--verbose", "--no-save"],
{ verbosity: CommandVerbosity.PROGRESS })
.then((): typeof XDLPackage => {
return require(XDL_PACKAGE);
return customRequire(XDL_PACKAGE);
});
return xdlPackage;
}

Просмотреть файл

@ -10,6 +10,7 @@ import {PackagerStatusIndicator, PackagerStatus} from "./packagerStatusIndicator
import {SettingsHelper} from "./settingsHelper";
import {OutputChannelLogger} from "./log/OutputChannelLogger";
import * as nls from "vscode-nls";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
export interface MobilePlatformDeps {

Просмотреть файл

@ -8,6 +8,7 @@ import {PromiseUtil} from "../../common/node/promise";
import {PlistBuddy} from "./plistBuddy";
import {SimulatorPlist} from "./simulatorPlist";
import * as nls from "vscode-nls";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
export class IOSDebugModeManager {

Просмотреть файл

@ -16,6 +16,7 @@ import {TelemetryHelper} from "../../common/telemetryHelper";
import { InternalErrorCode } from "../../common/error/internalErrorCode";
import * as nls from "vscode-nls";
import { AppLauncher } from "../appLauncher";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
export class IOSPlatform extends GeneralMobilePlatform {

Просмотреть файл

@ -13,6 +13,7 @@ import { ErrorHelper } from "../../common/error/errorHelper";
import { InternalErrorCode } from "../../common/error/internalErrorCode";
import { ProjectVersionHelper } from "../../common/projectVersionHelper";
import { getFileNameWithoutExtension } from "../../common/utils";
import customRequire from "../../common/customRequire";
export interface ConfigurationData {
fullProductName: string;
@ -178,7 +179,7 @@ export class PlistBuddy {
} else {
iOSCliFolderName = "cli";
}
const findXcodeProject = require(path.join(projectRoot, `node_modules/@react-native-community/${iOSCliFolderName}/build/commands/runIOS/findXcodeProject`)).default;
const findXcodeProject = customRequire(path.join(projectRoot, `node_modules/@react-native-community/${iOSCliFolderName}/build/commands/runIOS/findXcodeProject`)).default;
const xcodeProject = findXcodeProject(fs.readdirSync(iosProjectRoot));
if (!xcodeProject) {
throw new Error(

Просмотреть файл

@ -12,6 +12,7 @@ import {ChildProcess} from "../../common/node/childProcess";
import {TelemetryHelper} from "../../common/telemetryHelper";
import * as nls from "vscode-nls";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
export class SimulatorPlist {

Просмотреть файл

@ -8,6 +8,7 @@ import {ErrorHelper} from "../common/error/errorHelper";
import * as path from "path";
import * as Q from "q";
import * as nls from "vscode-nls";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
/* Usage:

Просмотреть файл

@ -3,6 +3,7 @@
import {window, Disposable, StatusBarItem, StatusBarAlignment} from "vscode";
import * as nls from "vscode-nls";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
/**

Просмотреть файл

@ -4,6 +4,7 @@
import * as qr from "qr-image";
import { TextDocumentContentProvider, Uri } from "vscode";
import * as nls from "vscode-nls";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
export class QRCodeContentProvider implements TextDocumentContentProvider {

Просмотреть файл

@ -11,11 +11,9 @@ try {
}
// @endif
import * as Q from "q";
import * as path from "path";
import * as vscode from "vscode";
import * as semver from "semver";
import {FileSystem} from "../common/node/fileSystem";
import {CommandPaletteHandler} from "./commandPaletteHandler";
import {EntryPointHandler, ProcessType} from "../common/entryPointHandler";
import {ErrorHelper} from "../common/error/errorHelper";
@ -33,12 +31,13 @@ import {ReactNativeSessionManager} from "./reactNativeSessionManager";
import {ProjectsStorage} from "./projectsStorage";
import {AppLauncher} from "./appLauncher";
import * as nls from "vscode-nls";
import { getExtensionVersion } from "../common/extensionHelper";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
/* all components use the same packager instance */
const outputChannelLogger = OutputChannelLogger.getMainChannel();
const entryPointHandler = new EntryPointHandler(ProcessType.Extension, outputChannelLogger);
const fsUtil = new FileSystem();
let debugConfigProvider: vscode.Disposable;
const APP_NAME = "react-native-tools";
@ -47,9 +46,13 @@ interface ISetupableDisposable extends vscode.Disposable {
setup(): Q.Promise<any>;
}
export function activate(context: vscode.ExtensionContext): Q.Promise<void> {
outputChannelLogger.debug("Begin to activate...");
const appVersion = require(path.resolve(__dirname, "../../package.json")).version;
const appVersion = getExtensionVersion();
if (!appVersion) {
throw new Error(localize("ExtensionVersionNotFound", "Extension version is not found"));
}
outputChannelLogger.debug(`Extension version: ${appVersion}`);
const ExtensionTelemetryReporter = require("vscode-extension-telemetry").default;
const reporter = new ExtensionTelemetryReporter(APP_NAME, appVersion, Telemetry.APPINSIGHTS_INSTRUMENTATIONKEY);
@ -166,10 +169,6 @@ function onFolderAdded(context: vscode.ExtensionContext, folder: vscode.Workspac
return void 0;
});
}));
promises.push(entryPointHandler.runFunction("debugger.setupNodeDebuggerLocation",
ErrorHelper.getInternalError(InternalErrorCode.NodeDebuggerConfigurationFailed), () => {
return configureNodeDebuggerLocation();
}));
} else {
outputChannelLogger.debug(`react-native@${versions.reactNativeVersion} isn't supported`);
}
@ -199,14 +198,7 @@ function onFolderRemoved(context: vscode.ExtensionContext, folder: vscode.Worksp
}
}
function configureNodeDebuggerLocation(): Q.Promise<void> {
const nodeDebugExtension = vscode.extensions.getExtension("ms-vscode.node-debug2");
if (!nodeDebugExtension) {
return Q.reject<void>(ErrorHelper.getInternalError(InternalErrorCode.CouldNotFindLocationOfNodeDebugger));
}
const nodeDebugPath = nodeDebugExtension.extensionPath;
return fsUtil.writeFile(path.resolve(__dirname, "../", "debugger", "nodeDebugLocation.json"), JSON.stringify({ nodeDebugPath }));
}
function setupAndDispose<T extends ISetupableDisposable>(setuptableDisposable: T, context: vscode.ExtensionContext): Q.Promise<T> {
return setuptableDisposable.setup()

Просмотреть файл

@ -12,6 +12,7 @@ import {TelemetryHelper} from "../../common/telemetryHelper";
import {CommandExecutor} from "../../common/commandExecutor";
import {WindowsPlatform} from "./windowsPlatform";
import * as nls from "vscode-nls";
nls.config({ messageFormat: nls.MessageFormat.bundle, bundleFormat: nls.BundleFormat.standalone })();
const localize = nls.loadMessageBundle();
/**

Просмотреть файл

@ -122,7 +122,7 @@ export class Application {
logger: this.options.logger,
verbose: this.options.verbose,
log: this.options.log,
extraArgs,
extraArgs: this.options.extraArgs || extraArgs,
remote: this.options.remote,
web: this.options.web,
browser: this.options.browser,

Просмотреть файл

@ -37,6 +37,10 @@ export class StatusBar {
await this.code.waitForTextContent(`${this.mainSelector} .statusbar-item[title="${title}"]`, text);
}
public async waitForStatusbarLabel(text: string): Promise<void> {
await this.code.waitForElement(`${this.mainSelector} .statusbar-item[aria-label="${text}"]`);
}
private getSelector(element: StatusBarElement): string {
switch (element) {
case StatusBarElement.BRANCH_STATUS:

Просмотреть файл

@ -0,0 +1,41 @@
// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for details.
import { Application } from "../../automation";
import { runVSCode, RNworkspacePath } from "./main";
import * as assert from "assert";
import * as path from "path";
import { sleep, findStringInFile } from "./helpers/utilities";
import { SmokeTestsConstants } from "./helpers/smokeTestsConstants";
const startPackagerCommand = "Start Packager";
const packagerStartedCheck = "Запуск упаковщика";
export function setup() {
describe("Localization test", () => {
let app: Application;
afterEach(async () => {
if (app) {
await app.stop();
}
});
it("Test localization", async function () {
app = await runVSCode(RNworkspacePath, "ru");
console.log("Localization test: Starting packager");
await app.workbench.quickaccess.runCommand(startPackagerCommand);
await sleep(10 * 1000);
if (process.env.REACT_NATIVE_TOOLS_LOGS_DIR) {
console.log(`Localization test: Search for '${packagerStartedCheck}' string output`);
const found = findStringInFile(path.join(process.env.REACT_NATIVE_TOOLS_LOGS_DIR, SmokeTestsConstants.ReactNativeLogFileName), packagerStartedCheck);
if (found) {
console.log(`Localization test: Output found`);
} else {
assert.fail("Localized RU string is not found in log file");
}
} else {
assert.fail("REACT_NATIVE_TOOLS_LOGS_DIR is not defined");
}
});
});
}

Просмотреть файл

@ -9,6 +9,7 @@ import { AppiumHelper } from "./helpers/appiumHelper";
import { SmokeTestsConstants } from "./helpers/smokeTestsConstants";
import { setup as setupReactNativeDebugAndroidTests } from "./debugAndroid.test";
import { setup as setupReactNativeDebugiOSTests } from "./debugIos.test";
import { setup as setupLocalizationTests } from "./localization.test";
import { AndroidEmulatorHelper } from "./helpers/androidEmulatorHelper";
import { VSCodeHelper } from "./helpers/vsCodeHelper";
import { SetupEnvironmentHelper } from "./helpers/setupEnvironmentHelper";
@ -124,7 +125,7 @@ const userDataDir = path.join(repoRoot, SmokeTestsConstants.VSCodeUserDataDir);
const extensionsPath = path.join(testVSCodeDirectory, "extensions");
function createOptions(quality: Quality, workspaceOrFolder: string, dataDirFolderName: string): ApplicationOptions | null {
function createOptions(quality: Quality, workspaceOrFolder: string, dataDirFolderName: string, extraArgs?: string[]): ApplicationOptions | null {
if (!electronExecutablePath) {
return null;
}
@ -146,6 +147,7 @@ function createOptions(quality: Quality, workspaceOrFolder: string, dataDirFolde
logger: new MultiLogger(loggers),
verbose: true,
screenshotsPath: path.join(logsDir, "screenshots"),
extraArgs: extraArgs,
};
}
@ -207,11 +209,11 @@ async function setup(): Promise<void> {
}
let runName = 0;
export async function runVSCode(workspaceOrFolder: string): Promise<Application> {
export async function runVSCode(workspaceOrFolder: string, locale?: string): Promise<Application> {
runName++;
const extensionLogsDir = path.join(artifactsPath, runName.toString(), "extensionLogs");
process.env.REACT_NATIVE_TOOLS_LOGS_DIR = extensionLogsDir;
const options = createOptions(quality, workspaceOrFolder, runName.toString());
const options = createOptions(quality, workspaceOrFolder, runName.toString(), locale ? ["--locale", locale] : []);
const app = new Application(options!);
console.log(`Options for run #${runName}: ${JSON.stringify(options, null, 2)}`);
await app!.start();
@ -246,6 +248,7 @@ describe("Extension smoke tests", () => {
}
AppiumHelper.terminateAppium();
});
setupLocalizationTests();
if (process.platform === "darwin") {
const noSelectArgs = !testParams.RunAndroidTests && !testParams.RunIosTests && !testParams.RunBasicTests;
if (noSelectArgs) {