diff --git a/website/docs/en/api/_meta.json b/website/docs/en/api/_meta.json index 251ba45090a..1308531c176 100644 --- a/website/docs/en/api/_meta.json +++ b/website/docs/en/api/_meta.json @@ -4,7 +4,11 @@ "modules", "node-api", "hmr", - "loader-api", + { + "type": "dir", + "name": "loader-api", + "label": "Loader API" + }, { "type": "dir", "name": "plugin-api", diff --git a/website/docs/en/api/index.mdx b/website/docs/en/api/index.mdx index 4394d4c28f1..310d616d694 100644 --- a/website/docs/en/api/index.mdx +++ b/website/docs/en/api/index.mdx @@ -30,7 +30,7 @@ The Hot Module Replacement (HMR) improves the development experience by updating Loaders are transformations that are applied to the source code of a module. They are written as functions that accept source code as a parameter and return a new version of that code with transformations applied. -[Learn more about the loaders!](/api/loader-api) +[Learn more about the loaders!](/api/loader-api/index) ## Plugins diff --git a/website/docs/en/api/loader-api.mdx b/website/docs/en/api/loader-api.mdx deleted file mode 100644 index f819502c508..00000000000 --- a/website/docs/en/api/loader-api.mdx +++ /dev/null @@ -1,335 +0,0 @@ -import WebpackLicense from '@components/webpack-license'; - - - -# Loader API - -Rspack loader is designed to reuse the webpack loader, it is compatible with most of the webpack loader API, the rest of the API is still being implemented, so most of the webpack loader can already run in Rspack. - -::: info Webpack Loader API conformance -Check out [this](https://github.com/orgs/web-infra-dev/projects/10) page to see the status of Webpack Loader API conformance. -::: - -## Synchronous Loaders - -Either `return` or `this.callback` can be used to return the transformed content synchronously: - -```js title="sync-loader.js" -module.exports = function (content, map, meta) { - return someSyncOperation(content); -}; -``` - -The `this.callback` method is more flexible as it allows multiple arguments to be passed as opposed to only the `content`. - -```js title="sync-loader-with-multiple-results.js" -module.exports = function (content, map, meta) { - this.callback(null, someSyncOperation(content), map, meta); - return; // always return undefined when calling callback() -}; -``` - -::: info -Rspack, internally, will convert loaders into asynchronous regardless of it's a synchronous loader for technical and performance reason. -::: - -## Asynchronous Loaders - -For asynchronous loaders, `this.async` is used to retrieve the callback function: - -```js title="async-loader.js" -module.exports = function (content, map, meta) { - var callback = this.async(); - someAsyncOperation(content, function (err, result) { - if (err) return callback(err); - callback(null, result, map, meta); - }); -}; -``` - -```js title="async-loader-with-multiple-results.js" -module.exports = function (content, map, meta) { - var callback = this.async(); - someAsyncOperation(content, function (err, result, sourceMaps, meta) { - if (err) return callback(err); - callback(null, result, sourceMaps, meta); - }); -}; -``` - -## Inline loaders - -It's possible to specify loaders in an import statement, or any equivalent "importing" method. Separate loaders from the resource with `!`. Each part is resolved relative to the current directory. - -```js -import Styles from 'style-loader!css-loader?modules!./styles.css'; -``` - -It's possible to override any loaders, preLoaders and postLoaders from the configuration by prefixing the inline import statement: - -Prefixing with `!` will disable all configured normal loaders - -```js -import Styles from '!style-loader!css-loader?modules!./styles.css'; -``` - -Prefixing with `!!` will disable all configured loaders (preLoaders, loaders, postLoaders) - -```js -import Styles from '!!style-loader!css-loader?modules!./styles.css'; -``` - -Prefixing with `-!` will disable all configured preLoaders and loaders but not postLoaders - -```js -import Styles from '-!style-loader!css-loader?modules!./styles.css'; -``` - -Options can be passed with a query parameter, e.g. `?key=value&foo=bar`, or a JSON object, e.g. `?{"key":"value","foo":"bar"}`. - -## Pitching loader - -Every loader has two stages: `Normal` and `Pitching`. -There are some instances where the loader only cares about the **metadata** -behind a request and can ignore the results of the previous loader. -The pitch method on loaders is called from **left to right** before the loaders are actually executed (from right to left). - -For the following configuration of use: - -```js title="rspack.config.js" -module.exports = { - //... - module: { - rules: [ - { - //... - use: ['a-loader', 'b-loader', 'c-loader'], - }, - ], - }, -}; -``` - -These steps would occur: - -``` -|- a-loader `pitch` - |- b-loader `pitch` - |- c-loader `pitch` - |- requested module is picked up as a dependency - |- c-loader normal execution - |- b-loader normal execution -|- a-loader normal execution -``` - -Normally, if it the loader is simple enough which only exports the normal stage hook: - -```js -module.exports = function (source) {}; -``` - -Then, the pitching stage will be skipped. - -So why might a loader take advantage of the "pitching" phase? - -First, the data passed to the pitch method is exposed in the execution phase as well under this.data and could be useful for capturing and sharing information from earlier in the cycle. - -```js -module.exports = function (content) { - return someSyncOperation(content, this.data.value); -}; - -module.exports.pitch = function (remainingRequest, precedingRequest, data) { - data.value = 42; -}; -``` - -Second, if a loader delivers a result in the pitch method, the process turns around and skips the remaining loaders. -In our example above, if the b-loaders pitch method returned something: - -```js -module.exports = function (content) { - return someSyncOperation(content); -}; - -module.exports.pitch = function (remainingRequest, precedingRequest, data) { - if (someCondition()) { - return ( - 'module.exports = require(' + - JSON.stringify('-!' + remainingRequest) + - ');' - ); - } -}; -``` - -The steps above would be shortened to: - -``` -|- a-loader `pitch` - |- b-loader `pitch` returns a module -|- a-loader normal execution -``` - -For a real world example, `style-loader` leverages the second advantage to dispatch requests. -Please visit [style-loader](https://github.com/webpack-contrib/style-loader/blob/eb06baeb3ac4e3107732a21170b0a7f358c5423f/src/index.js#L39) for details. - -## Inline match resource - -A new inline request syntax was introduced in webpack v4. Prefixing `!=!` to a request will set the matchResource for this request. -When a `matchResource` is set, it will be used to match with the module.rules instead of the original resource. This can be useful if further loaders should be applied to the resource, or if the module type needs to be changed. - -Example: - -```js title="file.js" -/* STYLE: body { background: red; } */ -console.log('yep'); -``` - -A loader could transform the file into the following file and use the matchResource to apply the user-specified CSS processing rules: - -```js title="file.js (transformed by loader)" -import './file.js.css!=!extract-style-loader/getStyles!./file.js'; -console.log('yep'); -``` - -This will add a dependency to `extract-style-loader/getStyles!./file.js` and treat the result as file.js.css. -Because `module.rules` has a rule matching /\.css$/ and it will apply to this dependency. - -The loader could look like this: - -```js title="extract-style-loader/index.js" -const getStylesLoader = require.resolve('./getStyles'); - -module.exports = function (source) { - if (STYLES_REGEXP.test(source)) { - source = source.replace(STYLES_REGEXP, ''); - return `import ${JSON.stringify( - this.utils.contextify( - this.context || this.rootContext, - `${this.resource}.css!=!${getStylesLoader}!${this.remainingRequest}`, - ), - )};${source}`; - } - return source; -}; -``` - -```js title="extract-style-loader/getStyles.js" -module.exports = function (source) { - const match = source.match(STYLES_REGEXP); - return match[0]; -}; -``` - -## 'Raw' Loader - -By default, resource files are converted to UTF-8 strings and passed to the loader. loaders can receive raw `Buffer` by setting `raw` to `true`. Each loader can pass its processing results as `String` or `Buffer`, and the Rspack compiler will convert them to and from the loader. - -```js -module.exports = function (content) { - assert(content instanceof Buffer); - // ... -}; -module.exports.raw = true; -``` - -## `this.addContextDependency(directory: string)` - -Add the directory as a dependency for the loader results so that any changes to the files in the directory can be listened to. - -## `this.addDependency(file: string)` - -Add a file as a dependency on the loader results so that any changes to them can be listened to. For example, `sass-loader`, `less-loader` use this trick to recompile when the imported style files change. - -## `this.dependency(file: string)` - -Alias of `this.addDependency(file: string)`. - -## `this.addMissingDependency(file: string)` - -Add a non-existent file as a dependency on the loader results to make them listenable. - -## `this.clearDependencies()` - -Removes all dependencies of the loader result. - -## `this.async()` - -Tells Rspack that this loader will be called asynchronously. Returns `this.callback`. - -## `this.callback(err: Error | null, content: string | Buffer, sourceMap?: SourceMap, meta?: any)` - -Tell Rspack the result of the Loader processing. - -The first parameter must be `Error` or `null`, which marks the current module as a compilation failure, the second parameter is a `string` or `Buffer`, which indicates the contents of the file after the module has been processed by the loader, the third parameter is a source map that can be processed by the loader, and the fourth parameter is ignored by Rspack and can be anything (e.g. some metadata). - -## `this.cacheable(flag: boolean = true)` - -By default, the processing results of the loader are marked as cacheable. Calling this method and passing `false` turns off the loader's ability to cache processing results. - -## `this.context` - -The directory where the current module is located. - -## `this.rootContext` - -The directory where the project is configured in config - -## `this.emitError(err: Error)` - -Emit an error. Unlike `throw` and `this.callback(err)` in the loader, it does not mark the current module as a compilation failure, it just adds an error to Rspack's Compilation and displays it on the command line at the end of this compilation. - -## `this.emitWarning(warning: Error)` - -Emit a warning. - -## `this.emitFile(name: string, content: Buffer | string, sourceMap: SourceMap)` - -Emit a file - -## `this.getOptions(schema)` - -Extracts the given loader option, accepting an optional JSON schema as an argument. - -## `this.getResolve(options: ResolveOptions): resolve` - -Create a resolver like `this.resolve`. - -## `this.resolve(context: string, request: string, callback: (err: Error | null, result: string) => void)` - -Resolve a request. - -- `context` must be the absolute path to a directory. This directory is used as the starting location for resolving. -- `request` is the request to be resolved. -- `callback` is a callback function that gives the resolved path. - -## `this.mode` - -The value of [`mode`](/config/mode) is read when webpack is run. - -The possible values are: `'production'`, `'development'`, `'none'` - -## `this.resource` - -The path string of the current module. For example `'/abc/resource.js?query#hash'`. - -## `this.resourcePath` - -The path string of the current module, excluding the query and fragment parameters. For example `'/abc/resource.js?query#hash'` in `'/abc/resource.js'`. - -## `this.resourceQuery` - -The query parameter for the path string of the current module. For example `'?query'` in `'/abc/resource.js?query#hash'`. - -## `this.resourceFragment` - -The fragment parameter of the current module's path string. For example `'#hash'` in `'/abc/resource.js?query#hash'`. - -## `this.sourceMap` - -Whether a source map should be generated. - -## `this.getLogger(name?: string)` - -Get the logger of this compilation, through which messages can be logged. diff --git a/website/docs/en/api/loader-api/_meta.json b/website/docs/en/api/loader-api/_meta.json new file mode 100644 index 00000000000..7a710dbf561 --- /dev/null +++ b/website/docs/en/api/loader-api/_meta.json @@ -0,0 +1,8 @@ +[ + "index", + "examples", + "context", + "rspack-specific-properties", + "inline", + "inline-match-resource" +] diff --git a/website/docs/en/api/loader-api/context.mdx b/website/docs/en/api/loader-api/context.mdx new file mode 100644 index 00000000000..69ea6451305 --- /dev/null +++ b/website/docs/en/api/loader-api/context.mdx @@ -0,0 +1,181 @@ +import WebpackLicense from '@components/webpack-license'; + + + +# The Loader Context + +The loader context represents the properties that are available inside of a loader assigned to the `this` property. + +## this.addContextDependency() + +```ts +function addContextDependency(directory: string): void; +``` + +Add the directory as a dependency for the loader results so that any changes to the files in the directory can be listened to. + +## this.addDependency() + +```ts +function addDependency(file: string): void; +``` + +Add a file as a dependency on the loader results so that any changes to them can be listened to. For example, `sass-loader`, `less-loader` use this trick to recompile when the imported style files change. + +## this.dependency() + +```ts +function dependency(file: string): void; +``` + +Alias of `this.addDependency()`. + +## this.addMissingDependency() + +```ts +function addMissingDependency(file: string): void; +``` + +Add a non-existent file as a dependency on the loader results to make them listenable. + +## this.async() + +Tells Rspack that this loader will be called asynchronously. Returns `this.callback`. + +## this.cacheable() + +A function that sets the cacheable flag: + +```ts +function cacheable(flag: boolean = true): void; +``` + +By default, the processing results of the loader are marked as cacheable. Calling this method and passing `false` turns off the loader's ability to cache processing results. + +## this.callback() + +```ts +function callback( + err: Error | null, + content: string | Buffer, + sourceMap?: SourceMap, + meta?: any, +): void; +``` + +A function that can be called synchronously or asynchronously in order to return multiple results. The expected arguments are: + +1. The first parameter must be `Error` or `null`, which marks the current module as a compilation failure. +2. The second argument is a `string` or `Buffer`, which indicates the contents of the file after the module has been processed by the loader. +3. The third parameter is a source map that can be processed by the loader. +4. The fourth parameter is ignored by Rspack and can be anything (e.g. some metadata). + +## this.clearDependencies() + +```ts +function clearDependencies(): void; +``` + +Removes all dependencies of the loader result. + +## this.context + +The directory where the current module is located. + +## this.data + +A data object shared between the pitch and the normal phase. + +## this.emitError() + +```ts +function emitError(error: Error): void; +``` + +Emit an error. Unlike `throw` and `this.callback(err)` in the loader, it does not mark the current module as a compilation failure, it just adds an error to Rspack's Compilation and displays it on the command line at the end of this compilation. + +## this.emitWarning(warning: Error) + +```ts +function emitWarning(warning: Error): void; +``` + +Emit a warning. + +## this.emitFile() + +```ts +function emitFile( + name: string, + content: Buffer | string, + sourceMap: SourceMap, +): void; +``` + +Emit a file. + +## this.getOptions(schema) + +Extracts the given loader option, accepting an optional JSON schema as an argument. + +## this.getResolve() + +```ts +function getResolve(options: ResolveOptions): resolve; +``` + +Create a resolver like `this.resolve`. + +## this.resolve() + +```ts +function resolve( + context: string, + request: string, + callback: (err: Error | null, result: string) => void, +): void; +``` + +Resolve a request. + +- `context` must be the absolute path to a directory. This directory is used as the starting location for resolving. +- `request` is the request to be resolved. +- `callback` is a callback function that gives the resolved path. + +## this.mode + +The value of [`mode`](/config/mode) is read when Rspack is run. + +The possible values are: `'production'`, `'development'`, `'none'` + +## this.resource + +The path string of the current module. For example `'/abc/resource.js?query#hash'`. + +## this.resourcePath + +The path string of the current module, excluding the query and fragment parameters. For example `'/abc/resource.js?query#hash'` in `'/abc/resource.js'`. + +## this.resourceQuery + +The query parameter for the path string of the current module. For example `'?query'` in `'/abc/resource.js?query#hash'`. + +## this.resourceFragment + +The fragment parameter of the current module's path string. For example `'#hash'` in `'/abc/resource.js?query#hash'`. + +## this.rootContext + +The directory where the project is configured in config + +## this.sourceMap + +Whether a source map should be generated. + +## this.getLogger() + +```ts +function getLogger(name?: string): void; +``` + +Get the logger of this compilation, through which messages can be logged. diff --git a/website/docs/en/api/loader-api/examples.mdx b/website/docs/en/api/loader-api/examples.mdx new file mode 100644 index 00000000000..d5b9b4d88b5 --- /dev/null +++ b/website/docs/en/api/loader-api/examples.mdx @@ -0,0 +1,150 @@ +import WebpackLicense from '@components/webpack-license'; + + + +# Examples + +The following sections provide some basic examples of the different types of loaders. Note that the `map` and `meta` parameters are optional, see [`this.callback`](#thiscallbackerr-error--null-content-string--buffer-sourcemap-sourcemap-meta-any) below. + +## Synchronous Loaders + +Either `return` or `this.callback` can be used to return the transformed `content` synchronously: + +```js title="sync-loader.js" +module.exports = function (content, map, meta) { + return someSyncOperation(content); +}; +``` + +The `this.callback` method is more flexible as it allows multiple arguments to be passed as opposed to only the `content`. + +```js title="sync-loader-with-multiple-results.js" +module.exports = function (content, map, meta) { + this.callback(null, someSyncOperation(content), map, meta); + return; // always return undefined when calling callback() +}; +``` + +::: info +Rspack, internally, will convert loaders into asynchronous regardless of it's a synchronous loader for technical and performance reason. +::: + +## Asynchronous Loaders + +For asynchronous loaders, `this.async` is used to retrieve the `callback` function: + +```js title="async-loader.js" +module.exports = function (content, map, meta) { + var callback = this.async(); + someAsyncOperation(content, function (err, result) { + if (err) return callback(err); + callback(null, result, map, meta); + }); +}; +``` + +```js title="async-loader-with-multiple-results.js" +module.exports = function (content, map, meta) { + var callback = this.async(); + someAsyncOperation(content, function (err, result, sourceMaps, meta) { + if (err) return callback(err); + callback(null, result, sourceMaps, meta); + }); +}; +``` + +## 'Raw' Loader + +By default, resource files are converted to UTF-8 strings and passed to the loader. loaders can receive raw `Buffer` by setting `raw` to `true`. Each loader can pass its processing results as `String` or `Buffer`, and the Rspack compiler will convert them to and from the loader. + +```js title="raw-loader.js" +module.exports = function (content) { + assert(content instanceof Buffer); + // ... +}; +module.exports.raw = true; +``` + +## Pitching loader + +Loaders are **always** called from right to left. There are some instances where the loader only cares about the **metadata** behind a request and can ignore the results of the previous loader. The `pitch` method on loaders is called from **left to right** before the loaders are actually executed (from right to left). + +For the following configuration of `use`: + +```js title="rspack.config.js" +module.exports = { + //... + module: { + rules: [ + { + //... + use: ['a-loader', 'b-loader', 'c-loader'], + }, + ], + }, +}; +``` + +These steps would occur: + +``` +|- a-loader `pitch` + |- b-loader `pitch` + |- c-loader `pitch` + |- requested module is picked up as a dependency + |- c-loader normal execution + |- b-loader normal execution +|- a-loader normal execution +``` + +Normally, if it the loader is simple enough which only exports the normal stage hook: + +```js +module.exports = function (source) {}; +``` + +Then, the pitching stage will be skipped. + +So why might a loader take advantage of the "pitching" phase? + +First, the data passed to the pitch method is exposed in the execution phase as well under this.data and could be useful for capturing and sharing information from earlier in the cycle. + +```js +module.exports = function (content) { + return someSyncOperation(content, this.data.value); +}; + +module.exports.pitch = function (remainingRequest, precedingRequest, data) { + data.value = 42; +}; +``` + +Second, if a loader delivers a result in the pitch method, the process turns around and skips the remaining loaders. +In our example above, if the b-loaders pitch method returned something: + +```js +module.exports = function (content) { + return someSyncOperation(content); +}; + +module.exports.pitch = function (remainingRequest, precedingRequest, data) { + if (someCondition()) { + return ( + 'module.exports = require(' + + JSON.stringify('-!' + remainingRequest) + + ');' + ); + } +}; +``` + +The steps above would be shortened to: + +``` +|- a-loader `pitch` + |- b-loader `pitch` returns a module +|- a-loader normal execution +``` + +For a real world example, `style-loader` leverages the second advantage to dispatch requests. +Please visit [style-loader](https://github.com/webpack-contrib/style-loader/blob/eb06baeb3ac4e3107732a21170b0a7f358c5423f/src/index.js#L39) for details. diff --git a/website/docs/en/api/loader-api/index.mdx b/website/docs/en/api/loader-api/index.mdx new file mode 100644 index 00000000000..0bab72a38a5 --- /dev/null +++ b/website/docs/en/api/loader-api/index.mdx @@ -0,0 +1,5 @@ +# Compatibility Status + +Rspack is committed to being compatible with the loaders within the webpack ecosystem. We ensure that Rspack is as compatible as possible with the webpack loader API, allowing more existing webpack loaders to be directly used in Rspack. + +We have already made most of the webpack loader APIs compatible. You can visit [this page](https://github.com/orgs/web-infra-dev/projects/10) to learn about the current compatibility status of webpack loader APIs. diff --git a/website/docs/en/api/loader-api/inline-match-resource.mdx b/website/docs/en/api/loader-api/inline-match-resource.mdx new file mode 100644 index 00000000000..fc8b89ffd33 --- /dev/null +++ b/website/docs/en/api/loader-api/inline-match-resource.mdx @@ -0,0 +1,52 @@ +import WebpackLicense from '@components/webpack-license'; + + + +# Inline matchResource + +Prefixing `!=!` to a request will set the `matchResource` for this request. + +When a `matchResource` is set, it will be used to match with the `module.rules` instead of the original resource. This can be useful if further loaders should be applied to the resource, or if the module type needs to be changed. + +Example: + +```js title="file.js" +/* STYLE: body { background: red; } */ +console.log('yep'); +``` + +A loader could transform the file into the following file and use the `matchResource` to apply the user-specified CSS processing rules: + +```js title="file.js (transformed by loader)" +import './file.js.css!=!extract-style-loader/getStyles!./file.js'; +console.log('yep'); +``` + +This will add a dependency to `extract-style-loader/getStyles!./file.js` and treat the result as `file.js.css`. +Because `module.rules` has a rule matching `/\.css$/` and it will apply to this dependency. + +The loader could look like this: + +```js title="extract-style-loader/index.js" +const getStylesLoader = require.resolve('./getStyles'); + +module.exports = function (source) { + if (STYLES_REGEXP.test(source)) { + source = source.replace(STYLES_REGEXP, ''); + return `import ${JSON.stringify( + this.utils.contextify( + this.context || this.rootContext, + `${this.resource}.css!=!${getStylesLoader}!${this.remainingRequest}`, + ), + )};${source}`; + } + return source; +}; +``` + +```js title="extract-style-loader/getStyles.js" +module.exports = function (source) { + const match = source.match(STYLES_REGEXP); + return match[0]; +}; +``` diff --git a/website/docs/en/api/loader-api/inline.mdx b/website/docs/en/api/loader-api/inline.mdx new file mode 100644 index 00000000000..7bfbf953060 --- /dev/null +++ b/website/docs/en/api/loader-api/inline.mdx @@ -0,0 +1,33 @@ +import WebpackLicense from '@components/webpack-license'; + + + +# Inline loaders + +It's possible to specify loaders in an `import` statement, or any equivalent "importing" method. Separate loaders from the resource with `!`. Each part is resolved relative to the current directory. + +```js +import Styles from 'style-loader!css-loader?modules!./styles.css'; +``` + +It's possible to override any loaders, preLoaders and postLoaders from the configuration by prefixing the inline `import` statement: + +- Prefixing with `!` will disable all configured normal loaders + + ```js + import Styles from '!style-loader!css-loader?modules!./styles.css'; + ``` + +- Prefixing with `!!` will disable all configured loaders (preLoaders, loaders, postLoaders) + + ```js + import Styles from '!!style-loader!css-loader?modules!./styles.css'; + ``` + +- Prefixing with `-!` will disable all configured preLoaders and loaders but not postLoaders + + ```js + import Styles from '-!style-loader!css-loader?modules!./styles.css'; + ``` + +Options can be passed with a query parameter, e.g. `?key=value&foo=bar`, or a JSON object, e.g. `?{"key":"value","foo":"bar"}`. diff --git a/website/docs/en/api/loader-api/rspack-specific-properties.mdx b/website/docs/en/api/loader-api/rspack-specific-properties.mdx new file mode 100644 index 00000000000..f85a3d5fde5 --- /dev/null +++ b/website/docs/en/api/loader-api/rspack-specific-properties.mdx @@ -0,0 +1,21 @@ +import WebpackLicense from '@components/webpack-license'; + + + +# Rspack specific properties + +The loader interface provides all module relate information. However in rare cases you might need access to the compiler api itself. + +:::warning +Please note that using these Rspack specific properties will have a negative impact on your loaders compatibility. + +Therefore you should only use them as a last resort. Using them will reduce the portability of your loader. +::: + +## this.\_compilation + +Access to the current Compilation object of Rspack. + +## this.\_compiler + +Access to the current Compiler object of Rspack. diff --git a/website/docs/en/api/plugin-api/index.mdx b/website/docs/en/api/plugin-api/index.mdx index 0c9552405dd..45fcad65f5d 100644 --- a/website/docs/en/api/plugin-api/index.mdx +++ b/website/docs/en/api/plugin-api/index.mdx @@ -2,4 +2,4 @@ Rspack is committed to being compatible with the plugins within the webpack ecosystem. We ensure that Rspack is as compatible as possible with the webpack plugin API, allowing more existing webpack plugins to be directly used in Rspack. -You can visit [this page](https://github.com/orgs/web-infra-dev/projects/9) to learn about the current compatibility status of webpack plugin APIs. +We have already made most of the webpack plugin APIs compatible. You can visit [this page](https://github.com/orgs/web-infra-dev/projects/9) to learn about the current compatibility status of webpack plugin APIs. diff --git a/website/docs/en/blog/announcing-0-2.mdx b/website/docs/en/blog/announcing-0-2.mdx index 9bc88fe0f37..e787e32fa51 100644 --- a/website/docs/en/blog/announcing-0-2.mdx +++ b/website/docs/en/blog/announcing-0-2.mdx @@ -16,7 +16,7 @@ We look forward to you experiencing these new improvements in version 0.2, and w ### Loader -Version 0.2 has completed compatibility with most of the loader APIs, including: inline match resource, pitching loader, and inline loader. More APIs have further improved compatibility with webpack loaders, details of which can be found in our webpack compatibility updates [Loader API](/api/loader-api.html). +Version 0.2 has completed compatibility with most of the loader APIs, including: inline match resource, pitching loader, and inline loader. More APIs have further improved compatibility with webpack loaders, details of which can be found in our webpack compatibility updates [Loader API](/api/loader-api/index). ### Plugin Hooks diff --git a/website/docs/en/config/entry.mdx b/website/docs/en/config/entry.mdx index 9174e9d4c36..6668ad1e923 100644 --- a/website/docs/en/config/entry.mdx +++ b/website/docs/en/config/entry.mdx @@ -207,7 +207,7 @@ The format of the chunk generated by this entry as a library, for detailed confi ## Dynamic entry -If a function is passed then it will be invoked on every [make](/api/plugin-api#make) event. +If a function is passed then it will be invoked on every [make](/api/plugin-api/compiler-hooks#make) event. > Note that the `make` event triggers when webpack starts and for every invalidation when [watching for file changes](/config/watch). diff --git a/website/docs/en/config/resolve-loader.mdx b/website/docs/en/config/resolve-loader.mdx index 05fd03270e4..cdcfb44150b 100644 --- a/website/docs/en/config/resolve-loader.mdx +++ b/website/docs/en/config/resolve-loader.mdx @@ -40,5 +40,5 @@ require('!!amazing-loader!./amazing-file.js'); ``` ::: info Inline Loaders -The loader mentioned above uses the syntax of inline loaders. For details, please refer to [here](/api/loader-api#inline-loaders). +The loader mentioned above uses the syntax of inline loaders. For details, please refer to [here](/api/loader-api/inline). ::: diff --git a/website/docs/en/guide/features/loader.mdx b/website/docs/en/guide/features/loader.mdx index c3d3b892fe2..ffd700b4a4f 100644 --- a/website/docs/en/guide/features/loader.mdx +++ b/website/docs/en/guide/features/loader.mdx @@ -133,7 +133,7 @@ module.exports = { }; ``` -For details, you can refer to [loader-api](/api/loader-api) +For details, you can refer to [loader-api](/api/loader-api/index) ### Using Built-in Loader diff --git a/website/docs/zh/api/_meta.json b/website/docs/zh/api/_meta.json index 020807b4e6f..6d734059add 100644 --- a/website/docs/zh/api/_meta.json +++ b/website/docs/zh/api/_meta.json @@ -4,7 +4,11 @@ "modules", "node-api", "hmr", - "loader-api", + { + "type": "dir", + "name": "loader-api", + "label": "Loader API" + }, { "type": "dir", "name": "plugin-api", diff --git a/website/docs/zh/api/index.mdx b/website/docs/zh/api/index.mdx index 31a5f957ab3..9ccb68c1f31 100644 --- a/website/docs/zh/api/index.mdx +++ b/website/docs/zh/api/index.mdx @@ -30,7 +30,7 @@ Hot Module Replacement(HMR)通过在运行时更新浏览器中的模块而 Loader 用于模块源代码的转换。它们被编写为函数,接收源代码作为参数,并返回转换后的代码。 -[了解更多关于 Loader 的信息!](/api/loader-api) +[了解更多关于 Loader 的信息!](/api/loader-api/index) ## 插件 diff --git a/website/docs/zh/api/loader-api.mdx b/website/docs/zh/api/loader-api.mdx index 5384646d59f..5672ed841f3 100644 --- a/website/docs/zh/api/loader-api.mdx +++ b/website/docs/zh/api/loader-api.mdx @@ -10,325 +10,6 @@ Rspack Loader 在设计时就是为了复用 Webpack Loader,我们已兼容了 你可以查看 [这个](https://github.com/orgs/web-infra-dev/projects/10) 页面来了解目前 Webpack Loader API 的支持情况。 ::: -## 同步 Loader - -`return` 或 `this.callback` 都可以用来同步返回转换后的内容: - -```js title="sync-loader.js" -module.exports = function (content, map, meta) { - return someSyncOperation(content); -}; -``` - -`this.callback` 方法更灵活,因为它允许传递多个参数,而不是只有 `content`。 - -```js title="sync-loader-with-multiple-results.js" -module.exports = function (content, map, meta) { - this.callback(null, someSyncOperation(content), map, meta); - return; // 调用 callback()时总是返回未定义的结果 -}; -``` - -::: info -出于技术和性能方面的考虑,Rspack 内部会将所有 Loader 转换为异步 Loader。 -::: - -## 异步 Loader - -对于异步 Loader,`this.async` 被用来获取回调函数: - -```js title="async-loader.js" -module.exports = function (content, map, meta) { - var callback = this.async(); - someAsyncOperation(content, function (err, result) { - if (err) return callback(err); - callback(null, result, map, meta); - }); -}; -``` - -```js title="async-loader-with-multiple-results.js" -module.exports = function (content, map, meta) { - var callback = this.async(); - someAsyncOperation(content, function (err, result, sourceMaps, meta) { - if (err) return callback(err); - callback(null, result, sourceMaps, meta); - }); -}; -``` - -## 内联 loader(Inline loaders) - -可以在 `import` 语句中指定 Loader,或者任何同等的 "导入"方法。用 `!` 将 Loader 从资源中分离出来。每个部分都是相对于当前目录来解析的。 - -```js -import Styles from 'style-loader!css-loader?modules!./styles.css'; -``` - -通过在 inline import 语句中加前缀,可以覆盖配置中的任何 Loader、preLoaders 和 postLoaders: - -前缀为 `!` 时将禁用所有配置的 Normal Loader - -```js -import Styles from '!style-loader!css-loader?modules!./styles.css'; -``` - -前缀为 `!!` 时将禁用所有配置的 Loader(preLoaders、loaders、postLoaders)。 - -```js -import Styles from '!!style-loader!css-loader?modules!./styles.css'; -``` - -前缀为 `-!` 时将禁用所有配置的 preLoaders 和 loaders,但不包括 postLoaders - -```js -import Styles from '-!style-loader!css-loader?modules!./styles.css'; -``` - -选项可以用查询参数来传递,例如`?key=value&foo=bar`,或者是 JSON 对象,例如`?{"key": "value", "foo": "bar"}`。 - -## Pitching loader - -每个 Loader 都有两个阶段: `normal` 和 `pitching`。 -在某些情况下,Loader 只关心一个请求背后的**metadata**,并可以忽略前一个 Loader 的返回结果。 -在 Loader 实际执行之前(从右到左),Loader 上的 `pitch` 方法从**左到右**调用。 - -对于以下使用的配置: - -```js title="rspack.config.js" -module.exports = { - //... - module: { - rules: [ - { - //... - use: ['a-loader', 'b-loader', 'c-loader'] 、 - }, - ], - }, -}; -``` - -会得到这些步骤: - -``` -|-a-loader `pitch - |- b-loader `pitch `. - |-c-loader `pitch` - |- 所请求的模块被作为依赖收集起来 - |- c-loader正常执行 - |-b-loader正常执行 -|- a-loader 正常执行 -``` - -通常情况下,如果 Loader 足够简单以至于只导出了 normal 阶段的钩子: - -```js -module.exports = function (source) {}; -``` - -那么其 pitching 阶段将被跳过。 - -那么,"pitching" 阶段对于 Loader 来说有哪些优势呢? - -首先,传递给 `pitch` 方法的数据在执行阶段也暴露在 `this.data` 下,可以用来捕获和共享 loader 生命周期中早期的信息。 - -```js -module.exports = function (content) { - return someSyncOperation(content, this.data.value); -}; - -module.exports.pitch = function (remainRequest, precedingRequest, data) { - data.value = 42; -}; -``` - -第二,如果一个 Loader 在 `pitch` 方法中提供了一个结果,整个 Loader 链路就会翻转过来,跳过其余的 normal 阶段的 Loader 。 -在我们上面的例子中,如果 b-loaders 的 `pitch` 方法返回了一些内容: - -```js -module.exports = function (content) { - return someSyncOperation(content); -}; - -module.exports.pitch = function (remainingRequest, precedingRequest, data) { - if (someCondition()) { - return ( - 'module.exports = require(' + - JSON.stringify('-!' + remainingRequest) + - ');' - ); - } -}; -``` - -上面的步骤将被缩短为: - -``` -|- a-loader `pitch` - |- b-loader `pitch`返回一个模块 -|- a-loader 正常执行 -``` - -举一个现实世界的例子,`style-loader`利用第二个优点来做请求的调度。 -请访问 [style-loader](https://github.com/webpack-contrib/style-loader/blob/eb06baeb3ac4e3107732a21170b0a7f358c5423f/src/index.js#L39) 了解详情。 - ## Inline match resource -webpack v4 中引入了一种新的内联请求语法。 在一个请求前缀 `!=!` 将为这个请求设置匹配资源。 -当`matchResource`被设置时,它将被用来与 `module.rules` 而不是原始 resource 进行匹配。当如果有更多的 Loader 应该应用到 resource 上,或者需要改变模块的类型,这可能很有用。 - -例子: - -```js title="file.js" -/*STYLE: body { background: red; } */ -console.log('yep'); -``` - -Loader 可以将该文件转化为以下文件,并使用 matchResource 来应用用户指定的 CSS 处理规则: - -```js title="file.js (transformed by loader)" -import './file.js.css!=! extract-style-loader/getStyles!./file.js'; -console.log('yep'); -``` - -这会将 `extract-style-loader/getStyles!./file.js` 作为一个依赖添加到编译流程中,并将结果作为 `file.js.css`。 -当 `module.rules` 有一个匹配 `/\.css$/` 的规则时,将会被这个 resource 命中。 - -Loader 可以是这样的: - -```js title="extract-style-loader/index.js" -const getStylesLoader = require.resolve('./getStyles'); - -module.exports = function (source) { - if (STYLES_REGEXP.test(source)) { - source = source.replace(STYLES_REGEXP, ''); - return `import ${JSON.stringify( - this.utils.contextify( - this.context || this.rootContext, - `${this.resource}.css!=!${getStylesLoader}!${this.remainingRequest}`, - ), - )};${source}`; - } - return source; -}; -``` - -```js title="extract-style-loader/getStyles.js" -module.exports = function (source) { - const match = source.match(STYLES_REGEXP); - return match[0]; -}; -``` - -## 'Raw' Loader - -默认情况下,资源文件会被转化为 UTF-8 字符串,然后传给 loader。通过设置 `raw` 为 `true`,loader 可以接收原始的 `Buffer`。每一个 loader 都可以用 `String` 或者 `Buffer` 的形式传递它的处理结果。Compiler 将会把它们在 loader 之间相互转换。 - -```js -module.exports = function (content) { - assert(content instanceof Buffer); - // ... -}; -module.exports.raw = true; -``` - -## `this.addContextDependency(directory: string)` - -添加目录作为 loader 结果的依赖,使目录中文件的任何变化可以被监听到。 - -## `this.addDependency(file: string)` - -添加一个文件作为 loader 结果的依赖,使它们的任何变化可以被监听到。例如,`sass-loader`、`less-loader` 就使用了这个技巧,当导入的样式文件发生变化时就会重新编译。 - -## `this.dependency(file: string)` - -`this.addDependency(file: string)` 的别名。 - -## `this.addMissingDependency(file: string)` - -添加一个不存在的文件作为 loader 结果的依赖项,以使它们可监听。 - -## `this.clearDependencies()` - -移除 loader 结果的所有依赖。 - -## `this.async()` - -告诉 Rspack 这个 loader 将会异步被调用。返回 `this.callback`。 - -## `this.callback(err: Error | null, content: string | Buffer, sourceMap?: SourceMap, meta?: any)` - -将 Loader 处理后的结果告诉 Rspack。 - -第一个参数必须是 `Error` 或者 `null`,会标记当前模块为编译失败,第二个参数是一个 `string` 或者 `Buffer`,表示模块被该 Loader 处理后的文件内容,第三个参数是一个可以该 Loader 处理后的 source map,第四个参数会被 Rspack 忽略,可以是任何东西(例如一些元数据)。 - -## `this.cacheable(flag: boolean = true)` - -默认情况下,loader 的处理结果会被标记为可缓存。调用这个方法然后传入 `false`,可以关闭 loader 处理结果的缓存能力。 - -## `this.context` - -当前模块所在的目录。 - -## `this.rootContext` - -config 中配置的项目所在的目录 - -## `this.emitError(err: Error)` - -发出一个错误,与在 loader 中 `throw` 和 `this.callback(err)` 不同,它不会标记当前模块为编译失败,只会在 Rspack 的 Compilation 上添加一个错误,并在此次编译结束后显示在命令行中。 - -## `this.emitWarning(warning: Error)` - -发出一个警告。 - -## `this.emitFile(name: string, content: Buffer | string, sourceMap: SourceMap)` - -产生一个文件。 - -## `this.getOptions(schema)` - -提取给定的 loader 选项,接受一个可选的 JSON schema 作为参数。 - -## `this.getResolve(options: ResolveOptions): resolve` - -创建一个类似于 `this.resolve` 的解析函数。 - -## `this.resolve(context: string, request: string, callback: (err: Error | null, result: string) => void)` - -解析一个 request。 - -- `context` 必须是一个目录的绝对路径。此目录用作解析的起始位置。 -- `request` 是要被解析的 request。 -- `callback` 是一个处理解析路径的回调函数。 - -## `this.mode` - -当 webpack 运行时读取 [mode](/config/mode) 的值 - -可能的值为:`'production'`、`'development'`、`'none'` - -## `this.resource` - -当前模块的路径字符串。比如 `'/abc/resource.js?query#hash'`。 - -## `this.resourcePath` - -当前模块的路径字符串,不包括 query 和 fragment 参数。比如 `'/abc/resource.js?query#hash'` 中的 `'/abc/resource.js'`。 - -## `this.resourceQuery` - -当前模块的路径字符串的 query 参数。比如 `'/abc/resource.js?query#hash'` 中的 `'?query'`。 - -## `this.resourceFragment` - -当前模块的路径字符串的 fragment 参数。比如 `'/abc/resource.js?query#hash'` 中的 `'#hash'`。 - -## `this.sourceMap` - -是否应该生成一个 source map。 - -## `this.getLogger(name?: string)` - -获取此次编译过程的 logger,可通过该 logger 记录消息。 +webpack v4 中引入了一种新的内联请求语法。 diff --git a/website/docs/zh/api/loader-api/_meta.json b/website/docs/zh/api/loader-api/_meta.json new file mode 100644 index 00000000000..7a710dbf561 --- /dev/null +++ b/website/docs/zh/api/loader-api/_meta.json @@ -0,0 +1,8 @@ +[ + "index", + "examples", + "context", + "rspack-specific-properties", + "inline", + "inline-match-resource" +] diff --git a/website/docs/zh/api/loader-api/context.mdx b/website/docs/zh/api/loader-api/context.mdx new file mode 100644 index 00000000000..951f47823c9 --- /dev/null +++ b/website/docs/zh/api/loader-api/context.mdx @@ -0,0 +1,176 @@ +import WebpackLicense from '@components/webpack-license'; + + + +# Loader 上下文 + +Loader 上下文表示 loader 内部可用的属性,这些属性在 loader 中通过 `this` 属性进行访问。 + +## this.addContextDependency() + +```ts +function addContextDependency(directory: string): void; +``` + +添加目录作为 loader 结果的依赖,使目录中文件的任何变化可以被监听到。 + +## this.addDependency() + +```ts +function addDependency(file: string): void; +``` + +添加一个文件作为 loader 结果的依赖,使它们的任何变化可以被监听到。例如,`sass-loader`、`less-loader` 就使用了这个技巧,当导入的样式文件发生变化时就会重新编译。 + +## this.dependency() + +```ts +function dependency(file: string): void; +``` + +`this.addDependency()` 的别名。 + +## this.addMissingDependency() + +```ts +function addMissingDependency(file: string): void; +``` + +添加一个不存在的文件作为 loader 结果的依赖项,以使它们可监听。 + +## this.async() + +告诉 Rspack 这个 loader 将会异步被调用。返回 `this.callback`。 + +## this.cacheable() + +```ts +function cacheable(flag: boolean = true): void; +``` + +默认情况下,loader 的处理结果会被标记为可缓存。调用这个方法然后传入 `false`,可以关闭 loader 处理结果的缓存能力。 + +## this.clearDependencies() + +```ts +function clearDependencies(): void; +``` + +移除 loader 结果的所有依赖。 + +## this.callback() + +```ts +function callback( + err: Error | null, + content: string | Buffer, + sourceMap?: SourceMap, + meta?: any, +): void; +``` + +将 Loader 处理后的结果告诉 Rspack。 + +第一个参数必须是 `Error` 或者 `null`,会标记当前模块为编译失败,第二个参数是一个 `string` 或者 `Buffer`,表示模块被该 Loader 处理后的文件内容,第三个参数是一个可以该 Loader 处理后的 source map,第四个参数会被 Rspack 忽略,可以是任何东西(例如一些元数据)。 + +## this.context + +当前模块所在的目录。 + +## this.data + +用于在 pitch 和 normal 阶段之间共享数据。 + +## this.emitError() + +```ts +function emitError(err: Error): void; +``` + +发出一个错误,与在 loader 中 `throw` 和 `this.callback(err)` 不同,它不会标记当前模块为编译失败,只会在 Rspack 的 Compilation 上添加一个错误,并在此次编译结束后显示在命令行中。 + +## this.emitWarning() + +```ts +function emitWarning(warning: Error): void; +``` + +发出一个警告。 + +## this.emitFile() + +```ts +function emitFile( + name: string, + content: Buffer | string, + sourceMap: SourceMap, +): void; +``` + +产生一个文件。 + +## this.getOptions(schema) + +提取给定的 loader 选项,接受一个可选的 JSON schema 作为参数。 + +## this.getResolve() + +```ts +function getResolve(options: ResolveOptions): resolve; +``` + +创建一个类似于 `this.resolve` 的解析函数。 + +## this.resolve() + +```ts +function resolve( + context: string, + request: string, + callback: (err: Error | null, result: string) => void, +): void; +``` + +解析一个 request。 + +- `context` 必须是一个目录的绝对路径。此目录用作解析的起始位置。 +- `request` 是要被解析的 request。 +- `callback` 是一个处理解析路径的回调函数。 + +## this.mode + +当 Rspack 运行时读取 [mode](/config/mode) 的值 + +可能的值为:`'production'`、`'development'`、`'none'` + +## this.resource + +当前模块的路径字符串。比如 `'/abc/resource.js?query#hash'`。 + +## this.resourcePath + +当前模块的路径字符串,不包括 query 和 fragment 参数。比如 `'/abc/resource.js?query#hash'` 中的 `'/abc/resource.js'`。 + +## this.resourceQuery + +当前模块的路径字符串的 query 参数。比如 `'/abc/resource.js?query#hash'` 中的 `'?query'`。 + +## this.resourceFragment + +当前模块的路径字符串的 fragment 参数。比如 `'/abc/resource.js?query#hash'` 中的 `'#hash'`。 + +## this.rootContext + +config 中配置的项目所在的目录 + +## this.sourceMap + +是否应该生成一个 source map。 + +## this.getLogger() + +```ts +function getLogger(name?: string): void; +``` + +获取此次编译过程的 logger,可通过该 logger 记录消息。 diff --git a/website/docs/zh/api/loader-api/examples.mdx b/website/docs/zh/api/loader-api/examples.mdx new file mode 100644 index 00000000000..adb8668c1a2 --- /dev/null +++ b/website/docs/zh/api/loader-api/examples.mdx @@ -0,0 +1,150 @@ +import WebpackLicense from '@components/webpack-license'; + + + +# 示例 + +以下部分提供了不同类型 loader 的一些基本示例。请注意,`map` 和 `meta` 可选参数,请参见下面的 [`this.callback`](#thiscallbackerr-error--null-content-string--buffer-sourcemap-sourcemap-meta-any)。 + +## 同步 Loader + +`return` 或 `this.callback` 都可以用来同步返回转换后的内容: + +```js title="sync-loader.js" +module.exports = function (content, map, meta) { + return someSyncOperation(content); +}; +``` + +`this.callback` 方法更灵活,因为它允许传递多个参数,而不是只有 `content`。 + +```js title="sync-loader-with-multiple-results.js" +module.exports = function (content, map, meta) { + this.callback(null, someSyncOperation(content), map, meta); + return; // 调用 callback() 时总是返回未定义的结果 +}; +``` + +::: info +出于技术和性能方面的考虑,Rspack 内部会将所有 loader 转换为异步 loader。 +::: + +## 异步 Loader + +对于异步 Loader,`this.async` 被用于获取 `callback` 函数: + +```js title="async-loader.js" +module.exports = function (content, map, meta) { + var callback = this.async(); + someAsyncOperation(content, function (err, result) { + if (err) return callback(err); + callback(null, result, map, meta); + }); +}; +``` + +```js title="async-loader-with-multiple-results.js" +module.exports = function (content, map, meta) { + var callback = this.async(); + someAsyncOperation(content, function (err, result, sourceMaps, meta) { + if (err) return callback(err); + callback(null, result, sourceMaps, meta); + }); +}; +``` + +## 'Raw' Loader + +默认情况下,资源文件会被转化为 UTF-8 字符串,然后传给 loader。通过设置 `raw` 为 `true`,loader 可以接收原始的 `Buffer`。每一个 loader 都可以用 `String` 或者 `Buffer` 的形式传递它的处理结果。Compiler 将会把它们在 loader 之间相互转换。 + +```js +module.exports = function (content) { + assert(content instanceof Buffer); + // ... +}; +module.exports.raw = true; +``` + +## Pitching loader + +Loader **总是**从右向左被调用。有些情况下,loader 只关心请求背后的**元数据**,可以忽略之前 loader 的结果。在 loader 真正执行之前(从右向左),loader 上的 `pitch` 方法会从**左向右**被调用。 + +对于以下使用的配置: + +```js title="rspack.config.js" +module.exports = { + //... + module: { + rules: [ + { + //... + use: ['a-loader', 'b-loader', 'c-loader'] 、 + }, + ], + }, +}; +``` + +会得到这些步骤: + +``` +|-a-loader `pitch + |- b-loader `pitch `. + |-c-loader `pitch` + |- 所请求的模块被作为依赖收集起来 + |- c-loader正常执行 + |-b-loader正常执行 +|- a-loader 正常执行 +``` + +通常情况下,如果 loader 足够简单以至于只导出了 normal 阶段的钩子: + +```js +module.exports = function (source) {}; +``` + +那么其 pitching 阶段将被跳过。 + +那么,"pitching" 阶段对于 loader 来说有哪些优势呢? + +首先,传递给 `pitch` 方法的数据在执行阶段也暴露在 `this.data` 下,可以用来捕获和共享 loader 生命周期中早期的信息。 + +```js +module.exports = function (content) { + return someSyncOperation(content, this.data.value); +}; + +module.exports.pitch = function (remainRequest, precedingRequest, data) { + data.value = 42; +}; +``` + +第二,如果一个 loader 在 `pitch` 方法中提供了一个结果,整个 loader 链路就会翻转过来,跳过其余的 normal 阶段的 loader 。 +在我们上面的例子中,如果 b-loaders 的 `pitch` 方法返回了一些内容: + +```js +module.exports = function (content) { + return someSyncOperation(content); +}; + +module.exports.pitch = function (remainingRequest, precedingRequest, data) { + if (someCondition()) { + return ( + 'module.exports = require(' + + JSON.stringify('-!' + remainingRequest) + + ');' + ); + } +}; +``` + +上面的步骤将被缩短为: + +``` +|- a-loader `pitch` + |- b-loader `pitch`返回一个模块 +|- a-loader 正常执行 +``` + +一个实际应用的例子是 `style-loader`,它利用了第二个优势来处理请求的调度。 +请访问 [style-loader](https://github.com/webpack-contrib/style-loader/blob/eb06baeb3ac4e3107732a21170b0a7f358c5423f/src/index.js#L39) 了解详情。 diff --git a/website/docs/zh/api/loader-api/index.mdx b/website/docs/zh/api/loader-api/index.mdx new file mode 100644 index 00000000000..9da84de6b3f --- /dev/null +++ b/website/docs/zh/api/loader-api/index.mdx @@ -0,0 +1,5 @@ +# 兼容情况 + +Rspack 致力于兼容 webpack 生态中的 loader。我们确保 Rspack 尽可能地去兼容 webpack 的 loader API,使更多现有的 webpack loader 能够在 Rspack 中直接使用。 + +我们已兼容了大部分 webpack 的 loader API,你可以访问[这个页面](https://github.com/orgs/web-infra-dev/projects/10)来了解目前 webpack Loader API 的兼容情况。 diff --git a/website/docs/zh/api/loader-api/inline-match-resource.mdx b/website/docs/zh/api/loader-api/inline-match-resource.mdx new file mode 100644 index 00000000000..631544b4f69 --- /dev/null +++ b/website/docs/zh/api/loader-api/inline-match-resource.mdx @@ -0,0 +1,51 @@ +import WebpackLicense from '@components/webpack-license'; + + + +# 内联 matchResource + +在一个请求前缀 `!=!` 将为这个请求设置匹配资源。 +当 `matchResource` 被设置时,它将被用来与 `module.rules` 而不是原始资源进行匹配。当如果有更多的 loader 应该应用到资源上,或者需要改变模块的类型,这可能很有用。 + +例子: + +```js title="file.js" +/*STYLE: body { background: red; } */ +console.log('yep'); +``` + +Loader 可以将该文件转化为以下文件,并使用 `matchResource` 来应用用户指定的 CSS 处理规则: + +```js title="file.js (transformed by loader)" +import './file.js.css!=! extract-style-loader/getStyles!./file.js'; +console.log('yep'); +``` + +这会将 `extract-style-loader/getStyles!./file.js` 作为一个依赖添加到编译流程中,并将结果作为 `file.js.css`。 +当 `module.rules` 有一个匹配 `/\.css$/` 的规则时,将会被这个资源命中。 + +Loader 可以是这样的: + +```js title="extract-style-loader/index.js" +const getStylesLoader = require.resolve('./getStyles'); + +module.exports = function (source) { + if (STYLES_REGEXP.test(source)) { + source = source.replace(STYLES_REGEXP, ''); + return `import ${JSON.stringify( + this.utils.contextify( + this.context || this.rootContext, + `${this.resource}.css!=!${getStylesLoader}!${this.remainingRequest}`, + ), + )};${source}`; + } + return source; +}; +``` + +```js title="extract-style-loader/getStyles.js" +module.exports = function (source) { + const match = source.match(STYLES_REGEXP); + return match[0]; +}; +``` diff --git a/website/docs/zh/api/loader-api/inline.mdx b/website/docs/zh/api/loader-api/inline.mdx new file mode 100644 index 00000000000..97aedc63e23 --- /dev/null +++ b/website/docs/zh/api/loader-api/inline.mdx @@ -0,0 +1,33 @@ +import WebpackLicense from '@components/webpack-license'; + + + +# 内联 loader + +可以在 `import` 语句中指定 loader,或者任何同等的 "导入"方法。用 `!` 将 loader 从资源中分离出来。每个部分都是相对于当前目录来解析的。 + +```js +import Styles from 'style-loader!css-loader?modules!./styles.css'; +``` + +通过在 inline import 语句中加前缀,可以覆盖配置中的任何 loaders、preLoaders 和 postLoaders: + +前缀为 `!` 时将禁用所有配置的 Normal Loader + +```js +import Styles from '!style-loader!css-loader?modules!./styles.css'; +``` + +前缀为 `!!` 时将禁用所有配置的 loader(preLoaders、loaders、postLoaders)。 + +```js +import Styles from '!!style-loader!css-loader?modules!./styles.css'; +``` + +前缀为 `-!` 时将禁用所有配置的 preLoaders 和 loaders,但不包括 postLoaders + +```js +import Styles from '-!style-loader!css-loader?modules!./styles.css'; +``` + +选项可以用查询参数来传递,例如 `?key=value&foo=bar`,或者是 JSON 对象,例如 `?{"key": "value", "foo": "bar"}`。 diff --git a/website/docs/zh/api/loader-api/rspack-specific-properties.mdx b/website/docs/zh/api/loader-api/rspack-specific-properties.mdx new file mode 100644 index 00000000000..9096642ed3d --- /dev/null +++ b/website/docs/zh/api/loader-api/rspack-specific-properties.mdx @@ -0,0 +1,21 @@ +import WebpackLicense from '@components/webpack-license'; + + + +# Rspack 特有属性 + +Loader API 提供了所有模块相关的信息。然而,在极少数情况下,你可能需要访问编译器API本身。 + +:::warning 警告 +请注意,使用这些特定于 Rspack 的属性会对你的 loader 的兼容性产生负面影响。 + +因此,你应该将它们作为最后的手段使用。使用它们会降低你的 loader 的可移植性。 +::: + +## this.\_compilation + +访问Rspack当前的Compilation对象。 + +## this.\_compiler + +访问Rspack当前的Compiler对象。 diff --git a/website/docs/zh/api/plugin-api/index.mdx b/website/docs/zh/api/plugin-api/index.mdx index 6ee37ee7f86..3a1b2372478 100644 --- a/website/docs/zh/api/plugin-api/index.mdx +++ b/website/docs/zh/api/plugin-api/index.mdx @@ -2,4 +2,4 @@ Rspack 致力于兼容 webpack 生态中的插件。我们确保 Rspack 尽可能地去兼容 webpack 的插件 API,使更多现有的 webpack 插件能够在 Rspack 中直接使用。 -你可以访问[这个页面](https://github.com/orgs/web-infra-dev/projects/9)来了解目前 webpack 插件 API 的兼容情况。 +我们已兼容了大部分 webpack 的插件 API,你可以访问[这个页面](https://github.com/orgs/web-infra-dev/projects/9)来了解目前 webpack 插件 API 的兼容情况。 diff --git a/website/docs/zh/blog/announcing-0-2.mdx b/website/docs/zh/blog/announcing-0-2.mdx index 76833c22f4e..80016a77f2b 100644 --- a/website/docs/zh/blog/announcing-0-2.mdx +++ b/website/docs/zh/blog/announcing-0-2.mdx @@ -14,7 +14,7 @@ date: 2023-06-02 13:11:00 ### Loader -0.2 版本完成了 loader 大部分 API 的兼容,其中包括了 inline match resource,pitching loader,inline loader 等。更多的 API 进一步提升了对 Webpack loader 的兼容性,详情可以参考下方 webpack 兼容性更新。更多信息请参考 [Loader API](/api/loader-api.html) +0.2 版本完成了 loader 大部分 API 的兼容,其中包括了 inline match resource,pitching loader,inline loader 等。更多的 API 进一步提升了对 Webpack loader 的兼容性,详情可以参考下方 webpack 兼容性更新。更多信息请参考 [Loader API](/api/loader-api/index) ### Plugin Hooks diff --git a/website/docs/zh/config/entry.mdx b/website/docs/zh/config/entry.mdx index cf94f56a08b..f5e2dff93a7 100644 --- a/website/docs/zh/config/entry.mdx +++ b/website/docs/zh/config/entry.mdx @@ -207,7 +207,7 @@ module.exports = { ## 动态入口 -如果传入一个函数,那么它将会在每次 [make](/api/plugin-api#make) 事件中被调用。 +如果传入一个函数,那么它将会在每次 [make](/api/plugin-api/compiler-hooks#make) 事件中被调用。 > 要注意的是,`make` 事件在 webpack 启动和每当[监听文件变化](/config/watch)时都会触发。 diff --git a/website/docs/zh/config/resolve-loader.mdx b/website/docs/zh/config/resolve-loader.mdx index 3edac237c77..eb8a8d92112 100644 --- a/website/docs/zh/config/resolve-loader.mdx +++ b/website/docs/zh/config/resolve-loader.mdx @@ -40,5 +40,5 @@ require('!!amazing-loader!./amazing-file.js'); ``` ::: info 内联 loader -上述的 loader 使用的是内联 loader 的语法,详情请参考[这里](/api/loader-api#%E5%86%85%E8%81%94-loaderinline-loaders) +上述的 loader 使用的是内联 loader 的语法,详情请参考[这里](/api/loader-api/index) ::: diff --git a/website/docs/zh/guide/features/loader.mdx b/website/docs/zh/guide/features/loader.mdx index 077c1b329a3..79c496619b3 100644 --- a/website/docs/zh/guide/features/loader.mdx +++ b/website/docs/zh/guide/features/loader.mdx @@ -135,7 +135,7 @@ module.exports = { }; ``` -更多关于 Loader API 的信息,请参考 [loader-api](/api/loader-api) +更多关于 Loader API 的信息,请参考 [loader-api](/api/loader-api/index) ### 使用内置 Loader diff --git a/website/theme/components/HomeFooter/index.tsx b/website/theme/components/HomeFooter/index.tsx index 54a3df5e04f..3e7f6ed8071 100644 --- a/website/theme/components/HomeFooter/index.tsx +++ b/website/theme/components/HomeFooter/index.tsx @@ -42,7 +42,7 @@ function useFooterData() { }, { title: 'Loader API', - link: getLink('/api/loader-api'), + link: getLink('/api/loader-api/index'), }, ], },