diff --git a/lib/definitions/project.d.ts b/lib/definitions/project.d.ts index c02d342aab..6180f374ed 100644 --- a/lib/definitions/project.d.ts +++ b/lib/definitions/project.d.ts @@ -75,7 +75,8 @@ interface INsConfig { appResourcesPath?: string; shared?: boolean; previewAppSchema?: string; - overridePods?: string + overridePods?: string; + webpackConfigPath?: string; } interface IProjectData extends ICreateProjectData { @@ -106,6 +107,13 @@ interface IProjectData extends ICreateProjectData { */ previewAppSchema: string; + /** + * Defines the path to the configuration file passed to webpack process. + * By default this is the webpack.config.js at the root of the application. + * The value can be changed by setting `webpackConfigPath` in nsconfig.json. + */ + webpackConfigPath: string; + /** * Initializes project data with the given project directory. If none supplied defaults to --path option or cwd. * @param {string} projectDir Project root directory. diff --git a/lib/project-data.ts b/lib/project-data.ts index 813e2d616b..6f96f946f2 100644 --- a/lib/project-data.ts +++ b/lib/project-data.ts @@ -70,6 +70,7 @@ export class ProjectData implements IProjectData { public podfilePath: string; public isShared: boolean; public previewAppSchema: string; + public webpackConfigPath: string; constructor(private $fs: IFileSystem, private $errors: IErrors, @@ -145,6 +146,7 @@ export class ProjectData implements IProjectData { this.podfilePath = path.join(this.appResourcesDirectoryPath, this.$devicePlatformsConstants.iOS, constants.PODFILE_NAME); this.isShared = !!(this.nsConfig && this.nsConfig.shared); this.previewAppSchema = this.nsConfig && this.nsConfig.previewAppSchema; + this.webpackConfigPath = (this.nsConfig && this.nsConfig.webpackConfigPath) ? path.resolve(this.projectDir, this.nsConfig.webpackConfigPath) : path.join(this.projectDir, "webpack.config.js"); return; } diff --git a/lib/services/webpack/webpack-compiler-service.ts b/lib/services/webpack/webpack-compiler-service.ts index 10da3ceb94..0b353499c8 100644 --- a/lib/services/webpack/webpack-compiler-service.ts +++ b/lib/services/webpack/webpack-compiler-service.ts @@ -12,6 +12,7 @@ export class WebpackCompilerService extends EventEmitter implements IWebpackComp constructor( private $errors: IErrors, private $childProcess: IChildProcess, + public $fs: IFileSystem, public $hooksService: IHooksService, public $hostInfo: IHostInfo, private $logger: ILogger, @@ -153,15 +154,18 @@ export class WebpackCompilerService extends EventEmitter implements IWebpackComp @performanceLog() private async startWebpackProcess(platformData: IPlatformData, projectData: IProjectData, prepareData: IPrepareData): Promise { + if (!this.$fs.exists(projectData.webpackConfigPath)) { + this.$errors.fail(`The webpack configuration file ${projectData.webpackConfigPath} does not exist. Ensure you have such file or set correct path in nsconfig.json`); + } + const envData = this.buildEnvData(platformData.platformNameLowerCase, projectData, prepareData); const envParams = await this.buildEnvCommandLineParams(envData, platformData, projectData, prepareData); const additionalNodeArgs = semver.major(process.version) <= 8 ? ["--harmony"] : []; - const args = [ ...additionalNodeArgs, "--preserve-symlinks", path.join(projectData.projectDir, "node_modules", "webpack", "bin", "webpack.js"), - `--config=${path.join(projectData.projectDir, "webpack.config.js")}`, + `--config=${projectData.webpackConfigPath}`, ...envParams ]; diff --git a/npm-shrinkwrap.json b/npm-shrinkwrap.json index eb1117574b..400806a91c 100644 --- a/npm-shrinkwrap.json +++ b/npm-shrinkwrap.json @@ -1,6 +1,6 @@ { "name": "nativescript", - "version": "6.3.3", + "version": "6.4.0", "lockfileVersion": 1, "requires": true, "dependencies": { diff --git a/package.json b/package.json index 612a03d301..3f42f9ae0d 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "nativescript", "preferGlobal": true, - "version": "6.3.3", + "version": "6.4.0", "author": "Telerik ", "description": "Command-line interface for building NativeScript projects", "bin": { diff --git a/test/project-data.ts b/test/project-data.ts index 19ba822181..3cf98eceb2 100644 --- a/test/project-data.ts +++ b/test/project-data.ts @@ -42,7 +42,8 @@ describe("projectData", () => { return testInjector; }; - const prepareTest = (opts?: { packageJsonData?: { dependencies?: IStringDictionary, devDependencies: IStringDictionary }, nsconfigData?: { shared: boolean } }): IProjectData => { + const projectDir = "projectDir"; + const prepareTest = (opts?: { packageJsonData?: { dependencies?: IStringDictionary, devDependencies: IStringDictionary }, nsconfigData?: { shared?: boolean, webpackConfigPath?: string } }): IProjectData => { const testInjector = createTestInjector(); const fs = testInjector.resolve("fs"); fs.exists = (filePath: string) => filePath && (path.basename(filePath) === "package.json" || (path.basename(filePath) === "nsconfig.json" && opts && opts.nsconfigData)); @@ -64,7 +65,7 @@ describe("projectData", () => { }; const projectHelper: IProjectHelper = testInjector.resolve("projectHelper"); - projectHelper.projectDir = "projectDir"; + projectHelper.projectDir = projectDir; const projectData: IProjectData = testInjector.resolve("projectData"); projectData.initializeProjectData(); @@ -142,4 +143,23 @@ describe("projectData", () => { assert.isTrue(projectData.isShared); }); }); + + describe("webpackConfigPath", () => { + it("default path to webpack.config.js is set when nsconfig.json does not set value", () => { + const projectData = prepareTest(); + assert.equal(projectData.webpackConfigPath, path.join(projectDir, "webpack.config.js")); + }); + + it("returns correct path when full path is set in nsconfig.json", () => { + const pathToConfig = path.resolve(path.join("/testDir", "innerDir", "mywebpack.config.js")); + const projectData = prepareTest({ nsconfigData: { webpackConfigPath: pathToConfig } }); + assert.equal(projectData.webpackConfigPath, pathToConfig); + }); + + it("returns correct path when relative path is set in nsconfig.json", () => { + const pathToConfig = path.resolve(path.join("projectDir", "innerDir", "mywebpack.config.js")); + const projectData = prepareTest({ nsconfigData: { webpackConfigPath: path.join("./innerDir", "mywebpack.config.js") } }); + assert.equal(projectData.webpackConfigPath, pathToConfig); + }); + }); }); diff --git a/test/services/webpack/webpack-compiler-service.ts b/test/services/webpack/webpack-compiler-service.ts index 22fb85686d..8da3183c24 100644 --- a/test/services/webpack/webpack-compiler-service.ts +++ b/test/services/webpack/webpack-compiler-service.ts @@ -1,6 +1,7 @@ import { Yok } from "../../../lib/common/yok"; import { WebpackCompilerService } from "../../../lib/services/webpack/webpack-compiler-service"; import { assert } from "chai"; +import { ErrorsStub } from "../../stubs"; const iOSPlatformName = "ios"; const androidPlatformName = "android"; @@ -17,10 +18,13 @@ function createTestInjector(): IInjector { testInjector.register("hooksService", {}); testInjector.register("hostInfo", {}); testInjector.register("logger", {}); - testInjector.register("errors", {}); + testInjector.register("errors", ErrorsStub); testInjector.register("packageInstallationManager", {}); testInjector.register("mobileHelper", {}); testInjector.register("cleanupService", {}); + testInjector.register("fs", { + exists: (filePath: string) => true + }); return testInjector; } @@ -87,4 +91,22 @@ describe("WebpackCompilerService", () => { assert.deepEqual(androidResult.emittedFiles, ["bundle.hash6.hot-update.js", "hash6.hot-update.json"]); }); }); + + describe("compileWithWatch", () => { + it("fails when the value set for webpackConfigPath is not existant file", async () => { + const webpackConfigPath = "some path.js"; + testInjector.resolve("fs").exists = (filePath: string) => filePath !== webpackConfigPath; + await assert.isRejected(webpackCompilerService.compileWithWatch({ platformNameLowerCase: "android" }, { webpackConfigPath }, {}), + `The webpack configuration file ${webpackConfigPath} does not exist. Ensure you have such file or set correct path in nsconfig.json`); + }); + }); + + describe("compileWithoutWatch", () => { + it("fails when the value set for webpackConfigPath is not existant file", async () => { + const webpackConfigPath = "some path.js"; + testInjector.resolve("fs").exists = (filePath: string) => filePath !== webpackConfigPath; + await assert.isRejected(webpackCompilerService.compileWithoutWatch({ platformNameLowerCase: "android" }, { webpackConfigPath }, {}), + `The webpack configuration file ${webpackConfigPath} does not exist. Ensure you have such file or set correct path in nsconfig.json`); + }); + }); }); diff --git a/test/stubs.ts b/test/stubs.ts index 6e12d8a4ac..af3d18a719 100644 --- a/test/stubs.ts +++ b/test/stubs.ts @@ -328,6 +328,7 @@ export class NodePackageManagerStub implements INodePackageManager { export class ProjectDataStub implements IProjectData { projectDir: string; projectName: string; + webpackConfigPath: string; get platformsDir(): string { return this.platformsDirCache || (this.projectDir && join(this.projectDir, "platforms")) || ""; }