Replies: 2 comments 2 replies
-
inline loader syntax is deprecated in webpack in the future, if we didn't rely on it to implement our internal plugin, maybe we could defer it to future |
Beta Was this translation helpful? Give feedback.
1 reply
-
is rust regex syntax the same as javascript, or we may met same problem as esbuild |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Summary
The high level of this proposal is to support a webpack-like loader implementation on rspack. Loader implementation of webpack is a bit long. As result, this RFC is not the final version and will be implemented progressively.
Loader provides a way to support different kinds of sources to be processed with Rspack.
Motivation
The implementation of the current architecture of Rspack is the combination of
resolve
+load
+transform
, which causes some problems of common bundlers face (like Rollup). For example, due to the separation ofresolve
andload
, we cannot easily handle the Virtual Module correctly (Theid
itself could be polluted by other plugins).Another core reason for this is the architecture of Rspack is basically derived from the Webpack, which assures the architecture is sound and solid in most cases.
Guide-level explanation
Glossary
Resource related
resource
: The absolute path to the requested file withquery
andfragment
retained.resourcePath
: The absolute path to the requested file withoutquery
andfragment
. e.g./index.js
resourceQuery
: The query part to the requested file. e.g?vue=true&style
resourceFragment
: The fragment part to the requested file. e.g#some-fragment
scheme
: The starting protocol of each specifier, such asdata
indata:text/javascript, ...
.context
: The directory of the module. Can be used as a context for resolving other stuff.Progressive loader support
loaderContext
loaderResult
and loader composition for the user side(i.e. themodule.rules
part from webpack) and basic node binding. At the moment, amodule.rules[number].rule
can be used withtype
to interact with the natively-supported module typesdata:
for Virtual Module and some important loader features (something likethis.getResolve
)this.importModule
(MiniCSSExtractPlugin used this, but it seems not necessary for now and it's only an example), etc.)Loader configurations
Rust option
Node option
Loader API
Rust Loader API
Node Loader API
For each loader, the return value could either be synchronous or asynchronous. We use
getCode
andgetBuffer
pair to lazily evaluate the value that comes from the Rust side, which can be used to mitigate the communication overhead.It's worth noting that
getCode
is not safe for thoseBuffer
s who are not valid UTF-8 strings, under the hood, this API will convert anyBuffer
that comes from the Rust side withBuffer#toString
which is equal to the result ofString#from_utf8_lossy
as they both replaces the invalid characters with the replacement characterU+FFFD
.Reference-level explanation
Due to the support of the loader being our first priority for each loader work to proceed, we have to do this in a progressive way.
Rspack
Removing
resolve
,load
,transform
hookUnder the current implementation,
resolve
hooks can be called from plugins and share the result withload
hooks. This gives a huge benefit for writing virtual modules. However, from my perspective of view, writing virtual modules specifier that is out of the spec(which could be if you let it go with the import specifier analysis) will make the client code specialized for a certain bundler, which should be avoided. (See [#Prior art](#Prior art) to know more about the strategy webpack used to deal with this problem)From this RFC and on, Rspack will remove the
resolve
/load
/transform
hook support. Instead, rspack will provide adefaultResolver
, any other unexpected specifier will cause a program exception. For virtual modules, we will respect the spec and implement this withdata:
in Stage 2 of this RFC. Resolver implementations likethis.getResolve
(doc) will be available atLoaderContext
(Stage 2) if you want to use it in a loader.The successfully parsed specifier will be like this:
Loader Runner
A new crate
loader-runner
will be created for running loaders for each module. This would help us to make the testing easier.Rspack will find the matching rules and sort the loaders first and pass the result to the
LoaderRunner
. The result for each loader runner will be astruct
:The result of each loader runner can be regarded as the
transform
result before.The loader runner supports the plugin system as well to resolve the scheme-based specifier in later stages.
Interacting with natively-supported Module Types
As soon as the rspack finds the matching rules, the module type is consolidated by the
module_type
property in each rule. In the previous implementation of rspack, we determine the kind of module type for each module by looking up the extension of a file. After that, we trigger the corresponding parser registered for this module type to handle this with rspack core natively.Node binding
The basic idea of the Rspack node plugin and Loader is to treat them as a whole respectively, which avoids unnecessary overheads. Under the hood, node-binding uses
ThreadsafeFunction
to call from any native thread (see the source code from main)Performance optimization: lazy evaluations
We have two layers of overhead if we handle the API like the way webpack did before:
But It's also good to note that the communication with Buffer is not that much pain-in-the-ass. Here's the solution:
String
s toJsBuffer
s (source code), then from the Node side, we can create aBuffer
from that.getter
, we choosegetXXX
to explicitly handle the conversion. If the value passed to the JS side is binary-formatted, then there is not much overhead for reading aBuffer
.The JS loader runner basically looks like this:
Rationale and alternatives
From the perspective of the Loader architecture, this could be replaced by
resolve
+load
+transform
, but you can see the disadvantage in the motivation part.Prior art
For the forms of loader, see: loader plugin api design (Analysis) #315
Webpack
Basically, you can refer to State of the art for Webpack: Loader #482. But there are still some cases we missed out there and here go the details.
Built-in specifier resolving
Two types of specifier resolving
We all know that webpack internally uses enhanced-resolve to handle the resolving on the file system. Here we are talking about resolving logic for different types of specifiers. Currently, webpack supports two kinds of user-written specifiers.
query
andfragment
to itdata:
specified scheme-based import statements, it's in the specification(spec), and supported by Nodejs as well (doc)Implementations of the resolving logic
For the normal import statements, webpack handles this for you and it is implemented without an internal plugin (see the source code)
For scheme-based import statements, you can register a resolver like what webpack does in its internal plugin(see the source code):
request
andidentifier
Webpack strongly relies on string parsing for inline loader syntax and inline match resource syntax.
In the proceedings of module creation, webpack uses the
identifier
of a module (it could be a NormalModule) to determine whether it's a newly created module or it already exists. With the inline loader syntax and inline match resource syntax, It's hard for webpack to determine the identifier, so not only the inline loader syntax and inline match resource syntax are appended to theModule#identifier
, but also the stringified user-defined loader (see the Module Creation Data Module#identifier)Parcel
Resolve
For dealing with the issue of Virtual Module, Parcel resolvers may also return
code
directly. This allows programmatically generating virtual modules on demand. You must still return afilePath
as well, however, as this indicates where any dependencies in the code should be resolved relative to.Unresolved questions
Not available for Stage1
Future possibilities
This will be tracked in different stages of implementing this RFC
Beta Was this translation helpful? Give feedback.
All reactions