Skip to content

Commit 98cdfd6

Browse files
feat: allow setting custom webpack config file
Currently CLI passes the webpack.config.js at the root of the application as config to the spawned webpack process. This file is managed by both the developers and nativescript-dev-webpack (when you update this package, you often have to update the file, which overrides any custom settings). In order to allow easier upgrades and customizations, add an option in nsconfig.json (`webpackConfigPath`) to set the path to config file passed to webpack process. This way, the `webpack.config.js` can be managed by nativescript-dev-webpack and all customizations can be done in another file. The path to custom file can be set in nsconfig.json and CLI will pass it to webpack.
1 parent 74e5074 commit 98cdfd6

File tree

6 files changed

+63
-6
lines changed

6 files changed

+63
-6
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 chaned 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

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)