Skip to content

Commit ff200af

Browse files
committed
Allow setOutputPath to create nested directories
1 parent f35841a commit ff200af

File tree

2 files changed

+68
-17
lines changed

2 files changed

+68
-17
lines changed

lib/WebpackConfig.js

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,23 @@ class WebpackConfig {
129129
}
130130

131131
if (!fs.existsSync(outputPath)) {
132-
// for safety, we won't recursively create directories
133-
// this might be a sign that the user has specified
134-
// an incorrect path
135-
if (!fs.existsSync(path.dirname(outputPath))) {
136-
throw new Error(`outputPath directory does not exist: ${outputPath}. Please check the path you're passing to setOutputPath() or create this directory`);
132+
// If the parent of the output directory does not exist either
133+
// check if it is located under the context directory before
134+
// creating it and its parent.
135+
const parentPath = path.dirname(outputPath);
136+
if (!fs.existsSync(parentPath)) {
137+
const context = path.resolve(this.getContext());
138+
if (outputPath.indexOf(context) !== 0) {
139+
throw new Error(`outputPath directory "${outputPath}" does not exist and is not located under the context directory "${context}". Please check the path you're passing to setOutputPath() or create this directory.`);
140+
}
141+
142+
parentPath.split(path.sep).reduce((previousPath, directory) => {
143+
const newPath = path.resolve(previousPath, directory);
144+
if (!fs.existsSync(newPath)) {
145+
fs.mkdirSync(newPath);
146+
}
147+
return newPath;
148+
}, path.sep);
137149
}
138150

139151
fs.mkdirSync(outputPath);

test/WebpackConfig.js

Lines changed: 51 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,32 @@ function createConfig() {
2828
describe('WebpackConfig object', () => {
2929

3030
describe('setOutputPath', () => {
31+
const removeDirectory = (targetPath) => {
32+
if (fs.existsSync(targetPath)) {
33+
const files = fs.readdirSync(targetPath);
34+
for (const file of files) {
35+
const filePath = path.resolve(targetPath, file);
36+
if (fs.lstatSync(filePath).isDirectory()) {
37+
removeDirectory(filePath);
38+
} else {
39+
fs.unlinkSync(filePath);
40+
}
41+
}
42+
43+
fs.rmdirSync(targetPath);
44+
}
45+
};
46+
47+
// Make sure the newly created directories are removed
48+
// before and after each test
49+
const cleanupNewDirectories = () => {
50+
removeDirectory(path.resolve(__dirname, 'new_dir'));
51+
removeDirectory(path.resolve(__dirname, '..', 'new_dir'));
52+
};
53+
54+
beforeEach(cleanupNewDirectories);
55+
afterEach(cleanupNewDirectories);
56+
3157
it('use absolute, existent path', () => {
3258
const config = createConfig();
3359
config.setOutputPath(__dirname);
@@ -37,15 +63,12 @@ describe('WebpackConfig object', () => {
3763

3864
it('relative path, becomes absolute', () => {
3965
const config = createConfig();
40-
config.setOutputPath('assets');
66+
config.setOutputPath('new_dir');
4167

4268
// __dirname is the context
4369
expect(config.outputPath).to.equal(
44-
path.join(__dirname, '/assets')
70+
path.join(__dirname, '/new_dir')
4571
);
46-
47-
// cleanup!
48-
fs.rmdirSync(path.join(__dirname, '/assets'));
4972
});
5073

5174
it('non-existent path creates directory', () => {
@@ -56,23 +79,39 @@ describe('WebpackConfig object', () => {
5679

5780
const config = createConfig();
5881
config.setOutputPath(targetPath);
82+
expect(fs.existsSync(config.outputPath)).to.be.true;
83+
});
5984

85+
it('non-existent directory, 3 levels deep is created correctly', () => {
86+
var targetPath = path.join(__dirname, 'new_dir', 'subdir1', 'subdir2');
87+
if (fs.existsSync(targetPath)) {
88+
fs.rmdirSync(targetPath);
89+
}
90+
91+
const config = createConfig();
92+
config.setOutputPath(targetPath);
6093
expect(fs.existsSync(config.outputPath)).to.be.true;
94+
});
95+
96+
it('non-existent path outside of the context directory works if only one directory has to be created', () => {
97+
var targetPath = path.join(__dirname, '..', 'new_dir');
98+
if (fs.existsSync(targetPath)) {
99+
fs.rmdirSync(targetPath);
100+
}
61101

62-
// cleanup!
63-
fs.rmdirSync(targetPath);
102+
const config = createConfig();
103+
config.setOutputPath(targetPath);
104+
expect(fs.existsSync(config.outputPath)).to.be.true;
64105
});
65106

66-
it('non-existent directory, 2 levels deep throws error', () => {
67-
var targetPath = path.join(__dirname, 'new_dir', 'subdir');
107+
it('non-existent path outside of the context directory throws an error if more than one directory has to be created', () => {
108+
var targetPath = path.join(__dirname, '..', 'new_dir', 'subdir');
68109
if (fs.existsSync(targetPath)) {
69110
fs.rmdirSync(targetPath);
70111
}
71112

72113
const config = createConfig();
73-
expect(() => {
74-
config.setOutputPath(targetPath);
75-
}).to.throw('create this directory');
114+
expect(() => config.setOutputPath(targetPath)).to.throw('create this directory');
76115
});
77116
});
78117

0 commit comments

Comments
 (0)