Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings
This repository was archived by the owner on Aug 8, 2019. It is now read-only.
/docsPublic archive

how to write a loader

Andy Ray edited this pageOct 8, 2017 ·31 revisions

A loader is a node module exporting afunction.

This function is called when a resource should be transformed by this loader.

In the simple case, when only a single loader is applied to the resource, the loader is called with one parameter: the content of the resource file as string.

The loader can access theloader API on thethis context in the function.

A sync loader that only wants to give a one value can simplyreturn it. In every other case the loader can give back any number of values with thethis.callback(err, values...) function. Errors are passed to thethis.callback function or thrown in a sync loader.

The loader is expected to give back one or two values. The first value is a resulting JavaScript code as string or buffer. The second optional value is a SourceMap as JavaScript object.

In the complex case, when multiple loaders are chained, only the last loader gets the resource file and only the first loader is expected to give back one or two values (JavaScript and SourceMap). Values that any other loader give back are passed to the previous loader.

In other words the loading order for chained loaders goes from right to left or bottom to top.For example: lets say you have two loaders that go by the name offooLoader andbarLoader. You would like to executefooLoader and then pass the result of the transformation fromfooLoader finally tobarLoader.

You would add the following in your config file (assuming that both loaders are already defined):

module:{rules:[{test:/\.js/,use:[{loader:'barLoader'},{loader:'fooLoader'}]]}

Note that webpack currently only searches in your node modules folder for loaders. If these loaders are defined outside your node modules folder you would need to use theresolveLoader property to get webpack to include your loaders. For example lets say you have your custom loaders included in a folder calledloaders. You would have to add the following to your config file:

resolveLoader:{modules:['node_modules',path.resolve(__dirname,'loaders')]}

Examples

// Identity loadermodule.exports=function(source){returnsource;};
// Identity loader with SourceMap supportmodule.exports=function(source,map){this.callback(null,source,map);};
// raw-loader's source - just converts your file to a string with "module.exports=" appended// This is basically the simplest real world loader./*MIT License http://www.opensource.org/licenses/mit-license.phpAuthor Tobias Koppers @sokra*/module.exports=function(content){this.cacheable&&this.cacheable();this.value=content;return"module.exports = "+JSON.stringify(content);}module.exports.seperable=true;

Guidelines

(Ordered by priority, first one should get the highest priority)

Loaders should

do only a single task

Loaders can be chained. Create loaders for every step, instead of a loader that does everything at once.

This also means they should not convert to JavaScript if not necessary.

Example: Render HTML from a template file by applying the query parameters

I could write a loader that compiles the template from source, execute it and return a module that exports a string containing the HTML code. This is bad.

Instead I should write loaders for every task in this use case and apply them all (pipeline):

  • jade-loader: Convert template to a module that exports a function.
  • apply-loader: Takes a function exporting module and returns raw result by applying query parameters.
  • html-loader: Takes HTML and exports a string exporting module.

generate modules that are modular

Loader generated modules should respect the same design principles like normal modules.

Example: That's a bad design: (not modular, global state, ...)

require("any-template-language-loader!./xyz.atl");varhtml=anyTemplateLanguage.render("xyz");

flag itself cacheable if possible

Most loaders are cacheable, so they should flag itself as cacheable.

Just callcacheable in the loader.

// Cacheable identity loadermodule.exports=function(source){this.cacheable();returnsource;};

not keep state between runs and modules

A loader should be independent of other modules compiled (expect of these issued by the loader).

A loader should be independent of previous compilations of the same module.

mark dependencies

If a loader uses external resources (i. e. by reading from filesystem), theymust tell about that. This information is used to invalidate cacheable loaders and recompile in watch mode.

// Loader adding a headervarpath=require("path");module.exports=function(source){this.cacheable();varcallback=this.async();varheaderPath=path.resolve("header.js");this.addDependency(headerPath);fs.readFile(headerPath,"utf-8",function(err,header){if(err)returncallback(err);callback(null,header+"\n"+source);});};

resolve dependencies

In many languages there is some schema to specify dependencies. i. e. in css there is@import andurl(...). These dependencies should be resolved by the module system.

There are two options to do this:

  • Transform them torequires.
  • Use thethis.resolve function to resolve the path

Example 1 css-loader: The css-loader transform dependencies torequires, by replacing@imports with a require to the other stylesheet (processed with the css-loader too) andurl(...) with arequire to the referenced file.

Example 2 less-loader: The less-loader cannot transform@imports torequires, because all less files need to be compiled in one pass to track variables and mixins. Therefore the less-loader extends the less compiler with a custom path resolving logic. This custom logic usesthis.resolve to resolve the file with the configuration of the module system (aliasing, custom module directories, etc.).

If the language only accept relative urls (like css:url(file) always means./file), there is the~-convention to specify references to modules:

url(file) -> require("./file")url(~module) -> require("module")

extract common code

don't generate much code that is common in every module processed by that loader. Create a (runtime) file in the loader and generate arequire to that common code.

should not embed absolute paths

don't put absolute paths in to the module code. They break hashing when the root for the project is moved. There is a methodstringifyRequest in loader-utils which converts an absolute path to an relative one.

Example:

varloaderUtils=require("loader-utils");return"var runtime = require("+loaderUtils.stringifyRequest(this,"!"+require.resolve("module/runtime"))+");";

use a library aspeerDependencies when they wrap it

using a peerDependency allows the application developer to specify the exact version inpackage.json if desired. The dependency should be relatively open to allow updating the library without needing to publish a new loader version.

"peerDependencies":{"library":"^1.3.5"}

programmable objects asquery-option

there are situations where your loader requires programmable objects with functions which cannot stringified asquery-string. The less-loader, for example, provides the possibility to specify LESS-plugins. In these cases, a loader is allowed to extend webpack'soptions-object to retrieve that specific option. In order to avoid name collisions, however, it is important that the option is namespaced under the loader's camelCased npm-name.

Example:

// webpack.config.jsmodule.exports={  ...lessLoader:{lessPlugins:[newLessPluginCleanCSS({advanced:true})]}};

The loader should also allow to specify the config-key (e.g.lessLoader) viaquery. Seediscussion andexample implementation.

be added to thelist of loaders

Read more

Read more aboutloaders.

webpack 👍

Clone this wiki locally

[8]ページ先頭

©2009-2025 Movatter.jp