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

- - - - - - - - - -
- -
- Tobias Koppers -
- -
- Kees Kluskens -
- -
- Mo Bitar -
- - -

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

+ + + + + + + + + +
+ +
+ Tobias Koppers +
+ +
+ Kees Kluskens +
+ +
+ Mo Bitar +
+ + +

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