Skip to content

Commit

Permalink
feat(webpack): load hook initial implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
antfu committed Jul 25, 2021
1 parent 7152253 commit e671b62
Show file tree
Hide file tree
Showing 5 changed files with 141 additions and 96 deletions.
27 changes: 23 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,9 @@
"profile": "0x -o -D .profile -P 'autocannon -c 100 -p 10 -d 40 http://localhost:$PORT' ./hello.js",
"test": "yarn lint && jest"
},
"dependencies": {
"webpack-virtual-modules": "^0.4.3"
},
"devDependencies": {
"0x": "latest",
"@nuxtjs/eslint-config-typescript": "latest",
Expand All @@ -38,21 +41,37 @@
"connect": "latest",
"cookie": "latest",
"destr": "latest",
"enhanced-resolve": "^5.8.2",
"enhanced-resolve": "latest",
"eslint": "latest",
"express": "latest",
"get-port": "latest",
"jest": "latest",
"jiti": "latest",
"listhen": "latest",
"rollup": "latest",
"rollup": "^2.53.3",
"siroc": "latest",
"standard-version": "latest",
"supertest": "latest",
"ts-jest": "latest",
"typescript": "latest",
"ufo": "latest",
"vite": "latest",
"webpack": "latest"
"vite": "^2.4.3",
"webpack": "^5.46.0"
},
"peerDependencies": {
"rollup": "^2.50.0",
"vite": "^2.3.0",
"webpack": "^5.0.0"
},
"peerDependenciesMeta": {
"rollup": {
"optional": true
},
"vite": {
"optional": true
},
"webpack": {
"optional": true
}
}
}
4 changes: 4 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { Plugin as RollupPlugin } from 'rollup'
import type { Compiler as WebpackCompiler } from 'webpack'
import type { Plugin as VitePlugin } from 'vite'
import VirtualModulesPlugin from 'webpack-virtual-modules'

export {
RollupPlugin,
Expand All @@ -22,6 +23,9 @@ export interface UnpluginOptions {
rollup?: Partial<RollupPlugin>
webpack?: (compiler: WebpackCompiler) => void
vite?: Partial<VitePlugin>

// injected internal objects
__vfs?: VirtualModulesPlugin
}

export type UnpluginFactory<UserOptions> = (options?: UserOptions) => UnpluginOptions
Expand Down
142 changes: 74 additions & 68 deletions src/webpack/index.ts
Original file line number Diff line number Diff line change
@@ -1,88 +1,94 @@
import fs from 'fs'
import { join, resolve } from 'path'
import type { Resolver } from 'enhanced-resolve'
import VirtualModulesPlugin from 'webpack-virtual-modules'
import type { UnpluginInstance, UnpluginFactory, WebpackCompiler } from '../types'

export function getWebpackPlugin<UserOptions = {}> (
factory: UnpluginFactory<UserOptions>
): UnpluginInstance<UserOptions>['webpack'] {
class UnpluginWebpackPlugin {
// eslint-disable-next-line no-useless-constructor
constructor (public userOptions?: UserOptions) {}
return (userOptions?: UserOptions) => {
return {
apply (compiler: WebpackCompiler) {
const rawPlugin = factory(userOptions)
const loaderPath = resolve(__dirname, 'webpack/loaders')

apply (compiler: WebpackCompiler) {
const rawPlugin = factory(this.userOptions)
const loaderPath = resolve(__dirname, 'webpack/loaders')
if (!compiler.$unpluginContext) {
compiler.$unpluginContext = {}
}
compiler.$unpluginContext[rawPlugin.name] = rawPlugin

if (!compiler.$unpluginContext) {
compiler.$unpluginContext = {}
}
compiler.$unpluginContext[rawPlugin.name] = rawPlugin
if (rawPlugin.transform) {
compiler.options.module.rules.push({
include (id: string) {
if (rawPlugin.transformInclude) {
return rawPlugin.transformInclude(id)
} else {
return true
}
},
enforce: rawPlugin.enforce,
use: [{
loader: join(loaderPath, 'transform.cjs'),
options: {
unpluginName: rawPlugin.name
}
}]
})
}

if (rawPlugin.transform) {
compiler.options.module.rules.push({
include (id: string) {
if (rawPlugin.transformInclude) {
return rawPlugin.transformInclude(id)
} else {
return true
}
},
enforce: rawPlugin.enforce,
use: [{
loader: join(loaderPath, 'transform.cjs'),
options: {
unpluginName: rawPlugin.name
}
}]
})
}
if (rawPlugin.resolveId) {
const virtualModule = new VirtualModulesPlugin()
rawPlugin.__vfs = virtualModule
compiler.options.plugins.push(virtualModule)

if (rawPlugin.resolveId) {
const resolver = {
apply (resolver: Resolver) {
const target = resolver.ensureHook('resolve')
resolver
.getHook('described-resolve')
.tapAsync('unplugin', async (request: any, resolveContext: any, callback: any) => {
const resolved = await rawPlugin.resolveId!(request.request)
if (resolved != null) {
const newRequest = {
...request,
request: resolved
const resolver = {
apply (resolver: Resolver) {
const target = resolver.ensureHook('resolve')
resolver
.getHook('described-resolve')
.tapAsync('unplugin', async (request: any, resolveContext: any, callback: any) => {
const resolved = await rawPlugin.resolveId!(request.request)
if (resolved != null) {
const newRequest = {
...request,
request: resolved
}
if (!fs.existsSync(resolved)) {
virtualModule.writeModule(resolved, '')
}
resolver.doResolve(target, newRequest, null, resolveContext, callback)
} else {
callback()
}
resolver.doResolve(target, newRequest, null, resolveContext, callback)
} else {
callback()
}
})
})
}
}
}

compiler.options.resolve.plugins = compiler.options.resolve.plugins || []
compiler.options.resolve.plugins.push(resolver)
}
compiler.options.resolve.plugins = compiler.options.resolve.plugins || []
compiler.options.resolve.plugins.push(resolver)
}

// TODO: not working for virtual module
if (rawPlugin.load) {
compiler.options.module.rules.push({
include () {
return true
},
enforce: rawPlugin.enforce,
use: [{
loader: join(loaderPath, 'load.cjs'),
options: {
unpluginName: rawPlugin.name
}
}]
})
}
// TODO: not working for virtual module
if (rawPlugin.load) {
compiler.options.module.rules.push({
include () {
return true
},
enforce: rawPlugin.enforce,
use: [{
loader: join(loaderPath, 'load.cjs'),
options: {
unpluginName: rawPlugin.name
}
}]
})
}

if (rawPlugin.webpack) {
rawPlugin.webpack(compiler)
if (rawPlugin.webpack) {
rawPlugin.webpack(compiler)
}
}
}
}

return UserOptions => new UnpluginWebpackPlugin(UserOptions)
}
9 changes: 2 additions & 7 deletions src/webpack/loaders/load.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,16 +6,11 @@ export default async function load (this: LoaderContext<any>, source: string) {
const { unpluginName } = this.query
const plugin = this._compiler?.$unpluginContext[unpluginName]

if (!plugin?.resolveId || !plugin?.load) {
if (!plugin?.load) {
return callback(null, source)
}

const id = await plugin.resolveId(this.resource)
if (id == null) {
return callback(null, source)
}

const res = await plugin.load(id)
const res = await plugin.load(this.resource)

if (res == null) {
callback(null, source)
Expand Down
55 changes: 38 additions & 17 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -845,7 +845,7 @@
jest-diff "^26.0.0"
pretty-format "^26.0.0"

"@types/json-schema@*":
"@types/json-schema@*", "@types/json-schema@^7.0.8":
version "7.0.8"
resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.8.tgz#edf1bf1dbf4e04413ca8e5b17b3b7d7d54b59818"
integrity sha512-YSBPTLTVm2e2OoQIDYx8HaeWJ5tTToLH67kXR7zYNGupXMEHa2++G8k+DczX2cFVgalypqtyZIcU19AFcmOpmg==
Expand Down Expand Up @@ -2806,7 +2806,7 @@ end-of-stream@^1.0.0, end-of-stream@^1.1.0:
dependencies:
once "^1.4.0"

enhanced-resolve@^5.8.0, enhanced-resolve@^5.8.2:
enhanced-resolve@^5.8.0, enhanced-resolve@latest:
version "5.8.2"
resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-5.8.2.tgz#15ddc779345cbb73e97c611cd00c01c1e7bf4d8b"
integrity sha512-F27oB3WuHDzvR2DOGNTaYy0D5o0cnrv8TeI482VM4kYgQd/FT9lUQwuNsJ0oOHtBUq7eiW5ytqzp7nBFknL+GA==
Expand Down Expand Up @@ -6299,7 +6299,7 @@ [email protected]:
joycon "^3.0.1"
jsonc-parser "^3.0.0"

rollup@^2.38.5, rollup@latest:
rollup@^2.38.5:
version "2.53.1"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.53.1.tgz#b60439efd1eb41bdb56630509bd99aae78b575d3"
integrity sha512-yiTCvcYXZEulNWNlEONOQVlhXA/hgxjelFSjNcrwAAIfYx/xqjSHwqg/cCaWOyFRKr+IQBaXwt723m8tCaIUiw==
Expand All @@ -6313,6 +6313,13 @@ rollup@^2.52.2:
optionalDependencies:
fsevents "~2.3.2"

rollup@^2.53.3:
version "2.53.3"
resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.53.3.tgz#14b0e57f0874d4ad23bdbb13050cf70bcd1eabf7"
integrity sha512-79QIGP5DXz5ZHYnCPi3tLz+elOQi6gudp9YINdaJdjG0Yddubo6JRFUM//qCZ0Bap/GJrsUoEBVdSOc4AkMlRA==
optionalDependencies:
fsevents "~2.3.2"

run-parallel@^1.1.9:
version "1.2.0"
resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.2.0.tgz#66d1368da7bdf921eb9d95bd1a9229e7f21a43ee"
Expand Down Expand Up @@ -6358,6 +6365,15 @@ schema-utils@^3.0.0:
ajv "^6.12.5"
ajv-keywords "^3.5.2"

schema-utils@^3.1.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281"
integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw==
dependencies:
"@types/json-schema" "^7.0.8"
ajv "^6.12.5"
ajv-keywords "^3.5.2"

selfsigned@^1.10.8:
version "1.10.11"
resolved "https://registry.yarnpkg.com/selfsigned/-/selfsigned-1.10.11.tgz#24929cd906fe0f44b6d01fb23999a739537acbe9"
Expand Down Expand Up @@ -7388,10 +7404,10 @@ vary@~1.1.2:
resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc"
integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=

vite@latest:
version "2.4.2"
resolved "https://registry.yarnpkg.com/vite/-/vite-2.4.2.tgz#07d00615775c808530bc9f65641062b349b67929"
integrity sha512-2MifxD2I9fjyDmmEzbULOo3kOUoqX90A58cT6mECxoVQlMYFuijZsPQBuA14mqSwvV3ydUsqnq+BRWXyO9Qa+w==
vite@^2.4.3:
version "2.4.3"
resolved "https://registry.yarnpkg.com/vite/-/vite-2.4.3.tgz#fe4aa78e9dd7d36bcb12eccbd52313b26cfadf77"
integrity sha512-iT6NPeiUUZ2FkzC3eazytOEMRaM4J+xgRQcNcpRcbmfYjakCFP4WKPJpeEz1U5JEKHAtwv3ZBQketQUFhFU3ng==
dependencies:
esbuild "^0.12.8"
postcss "^8.3.5"
Expand Down Expand Up @@ -7465,18 +7481,23 @@ webidl-conversions@^6.1.0:
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514"
integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w==

webpack-sources@^2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.3.0.tgz#9ed2de69b25143a4c18847586ad9eccb19278cfa"
integrity sha512-WyOdtwSvOML1kbgtXbTDnEW0jkJ7hZr/bDByIwszhWd/4XX1A3XMkrbFMsuH4+/MfLlZCUzlAdg4r7jaGKEIgQ==
webpack-sources@^2.3.1:
version "2.3.1"
resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-2.3.1.tgz#570de0af163949fe272233c2cefe1b56f74511fd"
integrity sha512-y9EI9AO42JjEcrTJFOYmVywVZdKVUfOvDUPsJea5GIr1JOEGFVqwlY2K098fFoIjOkDzHn2AjRvM8dsBZu+gCA==
dependencies:
source-list-map "^2.0.1"
source-map "^0.6.1"

webpack@latest:
version "5.44.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.44.0.tgz#97b13a02bd79fb71ac6301ce697920660fa214a1"
integrity sha512-I1S1w4QLoKmH19pX6YhYN0NiSXaWY8Ou00oA+aMcr9IUGeF5azns+IKBkfoAAG9Bu5zOIzZt/mN35OffBya8AQ==
webpack-virtual-modules@^0.4.3:
version "0.4.3"
resolved "https://registry.yarnpkg.com/webpack-virtual-modules/-/webpack-virtual-modules-0.4.3.tgz#cd597c6d51d5a5ecb473eea1983a58fa8a17ded9"
integrity sha512-5NUqC2JquIL2pBAAo/VfBP6KuGkHIZQXW/lNKupLPfhViwh8wNsu0BObtl09yuKZszeEUfbXz8xhrHvSG16Nqw==

webpack@^5.46.0:
version "5.46.0"
resolved "https://registry.yarnpkg.com/webpack/-/webpack-5.46.0.tgz#105d20d96f79db59b316b0ae54316f0f630314b5"
integrity sha512-qxD0t/KTedJbpcXUmvMxY5PUvXDbF8LsThCzqomeGaDlCA6k998D8yYVwZMvO8sSM3BTEOaD4uzFniwpHaTIJw==
dependencies:
"@types/eslint-scope" "^3.7.0"
"@types/estree" "^0.0.50"
Expand All @@ -7496,11 +7517,11 @@ webpack@latest:
loader-runner "^4.2.0"
mime-types "^2.1.27"
neo-async "^2.6.2"
schema-utils "^3.0.0"
schema-utils "^3.1.0"
tapable "^2.1.1"
terser-webpack-plugin "^5.1.3"
watchpack "^2.2.0"
webpack-sources "^2.3.0"
webpack-sources "^2.3.1"

whatwg-encoding@^1.0.5:
version "1.0.5"
Expand Down

0 comments on commit e671b62

Please sign in to comment.