diff --git a/.gitignore b/.gitignore
index 7bbe1a3..ff2c53b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,2 +1,10 @@
+# development
/node_modules
/coverage
+*.log
+
+# dotfiles
+.*
+!.gitignore
+*~
+*#*
diff --git a/README.md b/README.md
index 656b1ce..b9ef3bb 100644
--- a/README.md
+++ b/README.md
@@ -1,145 +1,155 @@
-[![npm][npm]][npm-url]
-[![node][node]][node-url]
-[![deps][deps]][deps-url]
-[![tests][tests]][tests-url]
-[![coverage][cover]][cover-url]
-[![chat][chat]][chat-url]
-
-
-
-
-
-
File Loader
-
-
-Install
-
-```bash
-npm install --save-dev file-loader
-```
-
-Usage
-
-By default the filename of the resulting file is the MD5 hash of the file's contents
-with the original extension of the required resource.
-
-``` javascript
-var url = require("file-loader!./file.png");
-// => emits file.png as file in the output directory and returns the public url
-// => returns i. e. "/public-path/0dcbbaa701328a3c262cfd45869e351f.png"
-```
-
-By default a file is emitted, however this can be disabled if required (e.g. for server
-side packages).
-
-``` javascript
-var url = require("file-loader?emitFile=false!./file.png");
-// => returns the public url but does NOT emit a file
-// => returns i. e. "/public-path/0dcbbaa701328a3c262cfd45869e351f.png"
-```
-
-#### Filename templates
-
-You can configure a custom filename template for your file using the query parameter `name`. For instance, to copy a file from your `context` directory into the output directory retaining the full directory structure, you might use `?name=[path][name].[ext]`.
-
-By default, the path and name you specify will output the file in that same directory and will also use that same URL path to access the file.
-
-You can specify custom output and public paths by using the `outputPath` and `publicPath` query name parameters:
-
-```
-use: "file-loader?name=[name].[ext]&publicPath=assets/foo/&outputPath=app/images/"
-```
-
-#### Filename template placeholders
-
-* `[ext]` the extension of the resource
-* `[name]` the basename of the resource
-* `[path]` the path of the resource relative to the `context` query parameter or option.
-* `[hash]` the hash of the content, `hex`-encoded `md5` by default
-* `[:hash::]` optionally you can configure
- * other `hashType`s, i. e. `sha1`, `md5`, `sha256`, `sha512`
- * other `digestType`s, i. e. `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`
- * and `length` the length in chars
-* `[N]` the N-th match obtained from matching the current file name against the query param `regExp`
-
-#### Examples
-
-``` javascript
-require("file-loader?name=js/[hash].script.[ext]!./javascript.js");
-// => js/0dcbbaa701328a3c262cfd45869e351f.script.js
-
-require("file-loader?name=html-[hash:6].html!./page.html");
-// => html-109fa8.html
-
-require("file-loader?name=[hash]!./flash.txt");
-// => c31e9820c001c9c4a86bce33ce43b679
-
-require("file-loader?name=[sha512:hash:base64:7].[ext]!./image.png");
-// => gdyb21L.png
-// use sha512 hash instead of md5 and with only 7 chars of base64
-
-require("file-loader?name=img-[sha512:hash:base64:7].[ext]!./image.jpg");
-// => img-VqzT5ZC.jpg
-// use custom name, sha512 hash instead of md5 and with only 7 chars of base64
-
-require("file-loader?name=picture.png!./myself.png");
-// => picture.png
-
-require("file-loader?name=[path][name].[ext]?[hash]!./dir/file.png")
-// => dir/file.png?e43b20c069c4a01867c31e98cbce33c9
-```
-
-Contributing
-
-Don't hesitate to create a pull request. Every contribution is appreciated. In development you can start the tests by calling `npm test`.
-
-Maintainers
-
-
-
-
-LICENSE
-
-MIT
-
-[npm]: https://img.shields.io/npm/v/file-loader.svg
-[npm-url]: https://npmjs.com/package/file-loader
-
-[node]: https://img.shields.io/node/v/file-loader.svg
-[node-url]: https://nodejs.org
-
-[deps]: https://david-dm.org/webpack-contrib/file-loader.svg
-[deps-url]: https://david-dm.org/webpack-contrib/file-loader
-
-[tests]: http://img.shields.io/travis/webpack-contrib/file-loader.svg
-[tests-url]: https://travis-ci.org/webpack-contrib/file-loader
-
-[cover]: https://coveralls.io/repos/github/webpack-contrib/file-loader/badge.svg
-[cover-url]: https://coveralls.io/github/webpack-contrib/file-loader
-
-[chat]: https://badges.gitter.im/webpack/webpack.svg
-[chat-url]: https://gitter.im/webpack/webpack
+[![npm][npm]][npm-url]
+[![node][node]][node-url]
+[![deps][deps]][deps-url]
+[![tests][tests]][tests-url]
+[![coverage][cover]][cover-url]
+[![chat][chat]][chat-url]
+
+
+
+
+
+
File Loader
+
+
+Install
+
+```bash
+npm install --save-dev file-loader
+```
+
+Usage
+
+By default the filename of the resulting file is the MD5 hash of the file's contents
+with the original extension of the required resource.
+
+``` javascript
+var url = require("file-loader!./file.png");
+// => emits file.png as file in the output directory and returns the public url
+// => returns i. e. "/public-path/0dcbbaa701328a3c262cfd45869e351f.png"
+```
+
+By default a file is emitted, however this can be disabled if required (e.g. for server
+side packages).
+
+``` javascript
+var url = require("file-loader?emitFile=false!./file.png");
+// => returns the public url but does NOT emit a file
+// => returns i. e. "/public-path/0dcbbaa701328a3c262cfd45869e351f.png"
+```
+
+#### Filename templates
+
+You can configure a custom filename template for your file using the query parameter `name`. For instance, to copy a file from your `context` directory into the output directory retaining the full directory structure, you might use `?name=[path][name].[ext]`.
+
+By default, the path and name you specify will output the file in that same directory and will also use that same URL path to access the file.
+
+You can specify custom output and public paths by using the `outputPath`, `publicPath` and `useRelativePath` query name parameters:
+
+```
+use: "file-loader?name=[name].[ext]&publicPath=assets/foo/&outputPath=app/images/"
+```
+
+`useRelativePath` should be `true` if you wish to generate relative URL to the each file context
+```javascript
+{
+ loader: 'file-loader',
+ query: {
+ useRelativePath: process.env.NODE_ENV === "production"
+ }
+}
+```
+
+#### Filename template placeholders
+
+* `[ext]` the extension of the resource
+* `[name]` the basename of the resource
+* `[path]` the path of the resource relative to the `context` query parameter or option.
+* `[hash]` the hash of the content, `hex`-encoded `md5` by default
+* `[:hash::]` optionally you can configure
+ * other `hashType`s, i. e. `sha1`, `md5`, `sha256`, `sha512`
+ * other `digestType`s, i. e. `hex`, `base26`, `base32`, `base36`, `base49`, `base52`, `base58`, `base62`, `base64`
+ * and `length` the length in chars
+* `[N]` the N-th match obtained from matching the current file name against the query param `regExp`
+
+#### Examples
+
+``` javascript
+require("file-loader?name=js/[hash].script.[ext]!./javascript.js");
+// => js/0dcbbaa701328a3c262cfd45869e351f.script.js
+
+require("file-loader?name=html-[hash:6].html!./page.html");
+// => html-109fa8.html
+
+require("file-loader?name=[hash]!./flash.txt");
+// => c31e9820c001c9c4a86bce33ce43b679
+
+require("file-loader?name=[sha512:hash:base64:7].[ext]!./image.png");
+// => gdyb21L.png
+// use sha512 hash instead of md5 and with only 7 chars of base64
+
+require("file-loader?name=img-[sha512:hash:base64:7].[ext]!./image.jpg");
+// => img-VqzT5ZC.jpg
+// use custom name, sha512 hash instead of md5 and with only 7 chars of base64
+
+require("file-loader?name=picture.png!./myself.png");
+// => picture.png
+
+require("file-loader?name=[path][name].[ext]?[hash]!./dir/file.png")
+// => dir/file.png?e43b20c069c4a01867c31e98cbce33c9
+```
+
+Contributing
+
+Don't hesitate to create a pull request. Every contribution is appreciated. In development you can start the tests by calling `npm test`.
+
+Maintainers
+
+
+
+
+LICENSE
+
+MIT
+
+[npm]: https://img.shields.io/npm/v/file-loader.svg
+[npm-url]: https://npmjs.com/package/file-loader
+
+[node]: https://img.shields.io/node/v/file-loader.svg
+[node-url]: https://nodejs.org
+
+[deps]: https://david-dm.org/webpack-contrib/file-loader.svg
+[deps-url]: https://david-dm.org/webpack-contrib/file-loader
+
+[tests]: http://img.shields.io/travis/webpack-contrib/file-loader.svg
+[tests-url]: https://travis-ci.org/webpack-contrib/file-loader
+
+[cover]: https://coveralls.io/repos/github/webpack-contrib/file-loader/badge.svg
+[cover-url]: https://coveralls.io/github/webpack-contrib/file-loader
+
+[chat]: https://badges.gitter.im/webpack/webpack.svg
+[chat-url]: https://gitter.im/webpack/webpack
\ No newline at end of file
diff --git a/index.js b/index.js
index 0d1861a..54d9861 100644
--- a/index.js
+++ b/index.js
@@ -2,6 +2,7 @@
MIT License http://www.opensource.org/licenses/mit-license.php
Author Tobias Koppers @sokra
*/
+var path = require("path");
var loaderUtils = require("loader-utils");
module.exports = function(content) {
@@ -11,9 +12,9 @@ module.exports = function(content) {
var query = loaderUtils.getOptions(this) || {};
var configKey = query.config || "fileLoader";
var options = this.options[configKey] || {};
-
var config = {
publicPath: false,
+ useRelativePath: false,
name: "[hash].[ext]"
};
@@ -27,29 +28,48 @@ module.exports = function(content) {
config[attr] = query[attr];
});
+ var context = config.context || this.options.context;
var url = loaderUtils.interpolateName(this, config.name, {
- context: config.context || this.options.context,
+ context: context,
content: content,
regExp: config.regExp
});
- var outputPath = url;
-
- var publicPath = "__webpack_public_path__ + " + JSON.stringify(url);
-
+ var outputPath = "";
if (config.outputPath) {
- // support functions as outputPath to generate them dynamically
- outputPath = typeof config.outputPath === "function"
- ? config.outputPath(url)
- : config.outputPath + url
+ // support functions as outputPath to generate them dynamically
+ outputPath = (
+ typeof config.outputPath === "function"
+ ? config.outputPath(url)
+ : config.outputPath
+ );
}
+ var filePath = this.resourcePath;
+ if (config.useRelativePath) {
+ var issuerContext = this._module && this._module.issuer && this._module.issuer.context || context;
+ var relativeUrl = issuerContext && path.relative(issuerContext, filePath).split(path.sep).join("/");
+ var relativePath = relativeUrl && path.dirname(relativeUrl) + "/";
+ if (~relativePath.indexOf("../")) {
+ outputPath = path.posix.join(outputPath, relativePath, url);
+ } else {
+ outputPath = relativePath + url;
+ }
+ url = relativePath + url;
+ } else if (outputPath) {
+ outputPath = outputPath + url;
+ url = outputPath;
+ } else {
+ outputPath = url;
+ }
+
+ var publicPath = "__webpack_public_path__ + " + JSON.stringify(url);
if (config.publicPath) {
// support functions as publicPath to generate them dynamically
publicPath = JSON.stringify(
- typeof config.publicPath === "function"
- ? config.publicPath(url)
- : config.publicPath + url
+ typeof config.publicPath === "function"
+ ? config.publicPath(url)
+ : config.publicPath + url
);
}
@@ -58,5 +78,6 @@ module.exports = function(content) {
}
return "module.exports = " + publicPath + ";";
-}
+};
+
module.exports.raw = true;
diff --git a/test/correct-filename.test.js b/test/correct-filename.test.js
index e73d63e..143eb86 100644
--- a/test/correct-filename.test.js
+++ b/test/correct-filename.test.js
@@ -61,7 +61,6 @@ describe("correct-filename", function() {
test("sntmopgidsdqrofkjywoyldtiij.txt", "/file.txt", "name=[hash:base26].[ext]");
test("sntmopgids.txt", "/file.txt", "name=[hash:base26:10].[ext]");
});
-
});
describe("publicPath option", function() {
@@ -70,4 +69,21 @@ describe("publicPath option", function() {
'module.exports = "http://cdn/81dc9bdb52d04dc20036dbd8313ed055.txt";'
);
});
+});
+
+describe("useRelativePath option", function() {
+ it("should be supported", function() {
+ run("/this/is/the/context/file.txt", "useRelativePath=true").result.should.be.eql(
+ 'module.exports = __webpack_public_path__ + \"./81dc9bdb52d04dc20036dbd8313ed055.txt\";'
+ );
+ run("/this/is/file.txt", "useRelativePath=true").result.should.be.eql(
+ 'module.exports = __webpack_public_path__ + \"../../81dc9bdb52d04dc20036dbd8313ed055.txt\";'
+ );
+ run("/this/file.txt", "context=/this/is/the/&useRelativePath=true").result.should.be.eql(
+ 'module.exports = __webpack_public_path__ + \"../../81dc9bdb52d04dc20036dbd8313ed055.txt\";'
+ );
+ run("/this/file.txt", "context=/&useRelativePath=true").result.should.be.eql(
+ 'module.exports = __webpack_public_path__ + \"this/81dc9bdb52d04dc20036dbd8313ed055.txt\";'
+ );
+ });
});
\ No newline at end of file