What is the difference between __dirname and ./ in Nodejs
Three different situations need to be considered.
- In Nodejs,
__dirnameand__filenameare always the directories in which these scripts reside. - By contrast,
./and../are the directories from which you run these scripts in Nodejs environment when you use libraries likepathandfs. - The paths in
requireare alway relative to these files.
FOr more detail information, here is the reference link on Stackoverflow.
I give an example below, our directory is like this:1
2
3
4
5
6webpack-learning/src
├── app
└── server
├── index.js
└── utils
└── pathtest.js
and the server/utils/pathtest.js contains1
2
3
4
5
6
7
8
9
10
11
12
13
14const chalk = require('chalk')
const path = require('path')
const fs = require('fs')
module.exports = function () {
console.log(chalk.yellow('__filename = %s \n__dirname = %s', __filename, path.resolve(__dirname)))
console.log(chalk.yellow('. = %s', path.resolve('.')))
console.log(require('../../../assets/media/config.json'))
console.log(chalk.yellow(fs.readFileSync(path.resolve(__dirname, '../../../assets/media/sometext.txt'), 'utf8')))
console.log(chalk.red.bgYellow('the next readFileSync() will throw out an exception if the working directory is not on the top of src!'))
console.log(chalk.red.bgYellow(fs.readFileSync('./assets/media/sometext.txt', 'utf8')))
}
the server/index.js is1
require('./utils/pathtest')()
When we run the script in the parent directory of src,1
➜ webpack-learning git:(testpath) node src/server/index.js
we get this result in the console.1
2
3
4
5
6
7__filename = %s
__dirname = %s /Users/qinqubo/Magicefire/Playground/webpack-learning/src/server/utils/pathtest.js /Users/qinqubo/Magicefire/Playground/webpack-learning/src/server/utils
. = %s /Users/qinqubo/Magicefire/Playground/webpack-learning
{ hello: 'world' }
some txt
the next readFileSync() will throw out an exception if the working directory is not on the top of src!
some txt
If we run this script in other directory, the second readFileSync function call will throw out an error in the console like this,1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18...
some txt
the next readFileSync() will throw out an exception if the working directory is not on the top of src!
fs.js:646
return binding.open(pathModule._makeLong(path), stringToFlags(flags), mode);
^
Error: ENOENT: no such file or directory, open './assets/media/sometext.txt'
at Object.fs.openSync (fs.js:646:18)
at Object.fs.readFileSync (fs.js:551:33)
at module.exports (/Users/qinqubo/Magicefire/Playground/webpack-learning/src/server/utils/pathtest.js:13:37)
at Object.<anonymous> (/Users/qinqubo/Magicefire/Playground/webpack-learning/src/server/index.js:1:90)
at Module._compile (module.js:652:30)
at Object.Module._extensions..js (module.js:663:10)
at Module.load (module.js:565:32)
at tryModuleLoad (module.js:505:12)
at Function.Module._load (module.js:497:3)
at Function.Module.runMain (module.js:693:10)
You can examine the differences between the two readFileSync function calls. Because the second one use ../ as its path, and these ./ and ../ are depended on the directory where you run the script. So the second one got an error.
I pushed the example code on Github, you can check out on the test-path branch.
The Paths in the webpack.config.js
Common Options
The Webpack is a compiler which reads a file specified by config.entry and recursively builds a dependency graph and then packages all these artifacts into a group of bundles(or a single bundle).

So a bunch of options of config in the webpack.config.js are about how to find the the input files in our project folder, and the others are used to figure out where the Webpack keep the output files. Some of these properties give absolute paths, some of them are relative to other options.
The table below gives some examples about the input options
| name | role | default value | dependency |
|---|---|---|---|
| context | The base directory, an absolute path, for resolving entry points and loaders from configuration. | The default value is process.cwd() but it’s recommended to replace it with an absolute address context: path.resolve(__dirname, 'app') |
|
| entry | The point or points to enter the application | context If entry is an absolute address, the context will be ignored |
|
| template(html-webpack-plugin) | require path to the template. | ‘’ | context |
When we discuss the output, we need to seperate 2 different situations. If we just let the Webpack package the bundle for us, then the Webpack create all output files on the disk. But
when we use the webpack-dev-server, the web server will mount these output files in the memory. The options are somewhat different.
Now we use webpack webpack --config ./build/webpack.config.js to create a distribute folder, here is the options we need to specify.
| name | role | default value | dependency |
|---|---|---|---|
| output.path | The output directory as an absolute path. | ||
| output.filename | This option determines the name of each output bundle. | The bundle is written to the directory specified by the output.path option |
|
| outputPath(file-loader) | output.path |
||
| filename(HtmlWebpackPlugin) | output.path |
When we start the webpack-dev-server, some of the options are different.
| name | role | default value | dependency |
|---|---|---|---|
| devServer.publicPath | Its role is same as the role of output.path. The differency is that it is mounted in the memory and as part of URL address which only be accessed from a web browser through the express server. |
‘/‘ | |
| devServer.contentBase | Tell the server where to serve content from. This is only necessary if you want to serve static files. devServer.publicPath will be used to determine where the bundles should be served from, and takes precedence. I think this option is useless and confused. Maybe when some resources are not packaged into our bundle, but can be accessed under the run time. In this case, maybe we would use this option. |
The Most Confused Part, publicPath
The most confused parts in the config of the Webpack are the two publicPaths. One is the devServer.publicPath we mention it before. The other is the output.publicPath. The latter in most case is a placeholder used by loaders and/or plugins to prefix(update) the URLs in the modules. In the production mode, we usually use this option to specify the CDN address, so we don’t need to manually update the URLs in all the files to point to the CDN.
1 | module.exports = { |
But, here is alway a But. When the output.publicPath is not a CDN address, it will influence the output result when we start the webpack-dev-server. I’m really bad at googling staff, I tried to find some articles, but they didn’t meet my expectations. And the document of Webpack is also terrible.
There are common mistakes we usually meet.
- If we assign the values for
devServer.publicPathandoutput.publicPath, but the values are different. The html cabn be loaded successfully, but the bundle and the other resource can not be accessed.1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17const config = {
output: {
publicPath: '/notdist/',
path: path.resolve(__dirname, '../dist'),
filename: '[name].bundle.js'
},
...
devServer: {
// static files served from here
publicPath: '/dist/',
port: 2000,
stats: 'errors-only',
open: true
},
}

- If both of these
publicPaths are not given values, the default value of thedevServer.publicPathis ‘/‘, and the default value of theoutput.publicPathis ‘’. That will be ok. But if we assigned a value to theoutput.publicPath, but didn’t give a value to thedevServer.publicPath, thedevServer.publicPathwill use theoutput.publicPathvalue!1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17const config = {
output: {
publicPath: '/dist/',
path: path.resolve(__dirname, '../dist'),
filename: '[name].bundle.js'
},
...
devServer: {
// static files served from here
// publicPath: '/dist/',
port: 2000,
stats: 'errors-only',
open: true
},
}
1 | NODE_ENV=development webpack-dev-server --config ./build/webpack.config.js |

It is not an error, but it is very confused:(
- The example before, we start the
output.publicPathwith the ‘/‘, so it is a server-relative path. So far everything is fine. But if we set this option using an address which is relative to HTML page, like ‘dist/‘1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17const config = {
output: {
publicPath: 'dist/',
path: path.resolve(__dirname, '../dist'),
filename: '[name].bundle.js'
},
...
devServer: {
// static files served from here
// publicPath: '/dist/',
// open app in localhost:2000
port: 2000,
stats: 'errors-only',
open: true
},
}
1 | NODE_ENV=development webpack-dev-server --config ./build/webpack.config.js |
loaders and plugins will update URLs with the html-relative path, here is the ‘dist/‘, but webpack output is served from ‘/dist/‘, we can access the html file at http://localhost:2000/dist/index.html, The linkers in this html file are pointing to the wrong addresses, such as src="dist/assets/media/webpacklogo.png" or src="dist/app.bundle.js" It is a relative path to the html file, but the html file and the bundle filea are already in the dist, and there is no sub-folder called dist

It is a disaster. My suggestion is avoiding using the derServer.publicPath and not using output.publicPath under the development mode. The only purpose of the output.publicPath is setting CDN address under the production mode.1
2
3
4
5
6
7
8
9
10
11
12
13
14const env = process.env.NODE_ENV
const config = {
...
output: {
// absolute path declaration
publicPath: env === 'development' ? '' : 'https://cdn.example.com/assets/',
path: path.resolve(__dirname, '../dist'),
filename: '[name].bundle.js'
},
...
}
The path of CleanWebpackPlugin
If we use CleanWebpackPlugin to remove the ‘dist’ folder, we must set the root value in its options when the config file is not in the root of the project.
1 | plugins: [ |
You can check out on the test-publicpath branch on Github.