Skip to content

Commit e143cbe

Browse files
Merge pull request #5216 from NativeScript/vladimirov/custom-webpack-config
feat: allow setting custom webpack config file
2 parents 74e5074 + 5634f41 commit e143cbe

File tree

8 files changed

+65
-8
lines changed

8 files changed

+65
-8
lines changed

lib/definitions/project.d.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ interface INsConfig {
7575
appResourcesPath?: string;
7676
shared?: boolean;
7777
previewAppSchema?: string;
78-
overridePods?: string
78+
overridePods?: string;
79+
webpackConfigPath?: string;
7980
}
8081

8182
interface IProjectData extends ICreateProjectData {
@@ -106,6 +107,13 @@ interface IProjectData extends ICreateProjectData {
106107
*/
107108
previewAppSchema: string;
108109

110+
/**
111+
* Defines the path to the configuration file passed to webpack process.
112+
* By default this is the webpack.config.js at the root of the application.
113+
* The value can be changed by setting `webpackConfigPath` in nsconfig.json.
114+
*/
115+
webpackConfigPath: string;
116+
109117
/**
110118
* Initializes project data with the given project directory. If none supplied defaults to --path option or cwd.
111119
* @param {string} projectDir Project root directory.

lib/project-data.ts

+2
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ export class ProjectData implements IProjectData {
7070
public podfilePath: string;
7171
public isShared: boolean;
7272
public previewAppSchema: string;
73+
public webpackConfigPath: string;
7374

7475
constructor(private $fs: IFileSystem,
7576
private $errors: IErrors,
@@ -145,6 +146,7 @@ export class ProjectData implements IProjectData {
145146
this.podfilePath = path.join(this.appResourcesDirectoryPath, this.$devicePlatformsConstants.iOS, constants.PODFILE_NAME);
146147
this.isShared = !!(this.nsConfig && this.nsConfig.shared);
147148
this.previewAppSchema = this.nsConfig && this.nsConfig.previewAppSchema;
149+
this.webpackConfigPath = (this.nsConfig && this.nsConfig.webpackConfigPath) ? path.resolve(this.projectDir, this.nsConfig.webpackConfigPath) : path.join(this.projectDir, "webpack.config.js");
148150
return;
149151
}
150152

lib/services/webpack/webpack-compiler-service.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ export class WebpackCompilerService extends EventEmitter implements IWebpackComp
1212
constructor(
1313
private $errors: IErrors,
1414
private $childProcess: IChildProcess,
15+
public $fs: IFileSystem,
1516
public $hooksService: IHooksService,
1617
public $hostInfo: IHostInfo,
1718
private $logger: ILogger,
@@ -153,15 +154,18 @@ export class WebpackCompilerService extends EventEmitter implements IWebpackComp
153154

154155
@performanceLog()
155156
private async startWebpackProcess(platformData: IPlatformData, projectData: IProjectData, prepareData: IPrepareData): Promise<child_process.ChildProcess> {
157+
if (!this.$fs.exists(projectData.webpackConfigPath)) {
158+
this.$errors.fail(`The webpack configuration file ${projectData.webpackConfigPath} does not exist. Ensure you have such file or set correct path in nsconfig.json`);
159+
}
160+
156161
const envData = this.buildEnvData(platformData.platformNameLowerCase, projectData, prepareData);
157162
const envParams = await this.buildEnvCommandLineParams(envData, platformData, projectData, prepareData);
158163
const additionalNodeArgs = semver.major(process.version) <= 8 ? ["--harmony"] : [];
159-
160164
const args = [
161165
...additionalNodeArgs,
162166
"--preserve-symlinks",
163167
path.join(projectData.projectDir, "node_modules", "webpack", "bin", "webpack.js"),
164-
`--config=${path.join(projectData.projectDir, "webpack.config.js")}`,
168+
`--config=${projectData.webpackConfigPath}`,
165169
...envParams
166170
];
167171

npm-shrinkwrap.json

+1-1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "nativescript",
33
"preferGlobal": true,
4-
"version": "6.3.3",
4+
"version": "6.4.0",
55
"author": "Telerik <[email protected]>",
66
"description": "Command-line interface for building NativeScript projects",
77
"bin": {

test/project-data.ts

+22-2
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,8 @@ describe("projectData", () => {
4242
return testInjector;
4343
};
4444

45-
const prepareTest = (opts?: { packageJsonData?: { dependencies?: IStringDictionary, devDependencies: IStringDictionary }, nsconfigData?: { shared: boolean } }): IProjectData => {
45+
const projectDir = "projectDir";
46+
const prepareTest = (opts?: { packageJsonData?: { dependencies?: IStringDictionary, devDependencies: IStringDictionary }, nsconfigData?: { shared?: boolean, webpackConfigPath?: string } }): IProjectData => {
4647
const testInjector = createTestInjector();
4748
const fs = testInjector.resolve("fs");
4849
fs.exists = (filePath: string) => filePath && (path.basename(filePath) === "package.json" || (path.basename(filePath) === "nsconfig.json" && opts && opts.nsconfigData));
@@ -64,7 +65,7 @@ describe("projectData", () => {
6465
};
6566

6667
const projectHelper: IProjectHelper = testInjector.resolve("projectHelper");
67-
projectHelper.projectDir = "projectDir";
68+
projectHelper.projectDir = projectDir;
6869

6970
const projectData: IProjectData = testInjector.resolve("projectData");
7071
projectData.initializeProjectData();
@@ -142,4 +143,23 @@ describe("projectData", () => {
142143
assert.isTrue(projectData.isShared);
143144
});
144145
});
146+
147+
describe("webpackConfigPath", () => {
148+
it("default path to webpack.config.js is set when nsconfig.json does not set value", () => {
149+
const projectData = prepareTest();
150+
assert.equal(projectData.webpackConfigPath, path.join(projectDir, "webpack.config.js"));
151+
});
152+
153+
it("returns correct path when full path is set in nsconfig.json", () => {
154+
const pathToConfig = path.resolve(path.join("/testDir", "innerDir", "mywebpack.config.js"));
155+
const projectData = prepareTest({ nsconfigData: { webpackConfigPath: pathToConfig } });
156+
assert.equal(projectData.webpackConfigPath, pathToConfig);
157+
});
158+
159+
it("returns correct path when relative path is set in nsconfig.json", () => {
160+
const pathToConfig = path.resolve(path.join("projectDir", "innerDir", "mywebpack.config.js"));
161+
const projectData = prepareTest({ nsconfigData: { webpackConfigPath: path.join("./innerDir", "mywebpack.config.js") } });
162+
assert.equal(projectData.webpackConfigPath, pathToConfig);
163+
});
164+
});
145165
});

test/services/webpack/webpack-compiler-service.ts

+23-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Yok } from "../../../lib/common/yok";
22
import { WebpackCompilerService } from "../../../lib/services/webpack/webpack-compiler-service";
33
import { assert } from "chai";
4+
import { ErrorsStub } from "../../stubs";
45

56
const iOSPlatformName = "ios";
67
const androidPlatformName = "android";
@@ -17,10 +18,13 @@ function createTestInjector(): IInjector {
1718
testInjector.register("hooksService", {});
1819
testInjector.register("hostInfo", {});
1920
testInjector.register("logger", {});
20-
testInjector.register("errors", {});
21+
testInjector.register("errors", ErrorsStub);
2122
testInjector.register("packageInstallationManager", {});
2223
testInjector.register("mobileHelper", {});
2324
testInjector.register("cleanupService", {});
25+
testInjector.register("fs", {
26+
exists: (filePath: string) => true
27+
});
2428

2529
return testInjector;
2630
}
@@ -87,4 +91,22 @@ describe("WebpackCompilerService", () => {
8791
assert.deepEqual(androidResult.emittedFiles, ["bundle.hash6.hot-update.js", "hash6.hot-update.json"]);
8892
});
8993
});
94+
95+
describe("compileWithWatch", () => {
96+
it("fails when the value set for webpackConfigPath is not existant file", async () => {
97+
const webpackConfigPath = "some path.js";
98+
testInjector.resolve("fs").exists = (filePath: string) => filePath !== webpackConfigPath;
99+
await assert.isRejected(webpackCompilerService.compileWithWatch(<any>{ platformNameLowerCase: "android" }, <any>{ webpackConfigPath }, <any>{}),
100+
`The webpack configuration file ${webpackConfigPath} does not exist. Ensure you have such file or set correct path in nsconfig.json`);
101+
});
102+
});
103+
104+
describe("compileWithoutWatch", () => {
105+
it("fails when the value set for webpackConfigPath is not existant file", async () => {
106+
const webpackConfigPath = "some path.js";
107+
testInjector.resolve("fs").exists = (filePath: string) => filePath !== webpackConfigPath;
108+
await assert.isRejected(webpackCompilerService.compileWithoutWatch(<any>{ platformNameLowerCase: "android" }, <any>{ webpackConfigPath }, <any>{}),
109+
`The webpack configuration file ${webpackConfigPath} does not exist. Ensure you have such file or set correct path in nsconfig.json`);
110+
});
111+
});
90112
});

test/stubs.ts

+1
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,7 @@ export class NodePackageManagerStub implements INodePackageManager {
328328
export class ProjectDataStub implements IProjectData {
329329
projectDir: string;
330330
projectName: string;
331+
webpackConfigPath: string;
331332
get platformsDir(): string {
332333
return this.platformsDirCache || (this.projectDir && join(this.projectDir, "platforms")) || "";
333334
}

0 commit comments

Comments
 (0)