Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(html): add HTML module support (
html/experimental
)
- Loading branch information
1 parent
f6e366b
commit 1be08a3
Showing
16 changed files
with
476 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
const { | ||
HTMLURLDependency, | ||
HTMLImportDependency | ||
} = require("./dependencies"); | ||
|
||
class HTMLDependencyPlugin { | ||
constructor(options) { | ||
this.plugin = "HTMLDependencyPlugin"; | ||
this.options = options; | ||
} | ||
|
||
apply(compiler) { | ||
const { plugin } = this; | ||
const { compilation } = compiler.hooks; | ||
|
||
compilation.tap(plugin, (compilation, { normalModuleFactory }) => { | ||
const { dependencyFactories, dependencyTemplates } = compilation; | ||
|
||
dependencyFactories.set(HTMLURLDependency, normalModuleFactory); | ||
dependencyFactories.set(HTMLImportDependency, normalModuleFactory); | ||
|
||
dependencyTemplates.set( | ||
HTMLImportDependency, | ||
new HTMLImportDependency.Template() | ||
); | ||
}); | ||
} | ||
} | ||
|
||
module.exports = HTMLDependencyPlugin; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
class HTMLGenerator { | ||
generate(module) { | ||
return module.originalSource(); | ||
} | ||
} | ||
|
||
module.exports = HTMLGenerator; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
const HTMLParser = require("./HTMLParser"); | ||
const HTMLGenerator = require("./HTMLGenerator"); | ||
|
||
const Template = require("webpack/lib/Template"); | ||
const { | ||
ConcatSource | ||
} = require("webpack-sources"); | ||
|
||
class HTMLModulesPlugin { | ||
constructor() { | ||
this.plugin = { | ||
name: "HTMLModulesPlugin" | ||
}; | ||
} | ||
|
||
apply(compiler) { | ||
const { plugin } = this; | ||
const { compilation } = compiler.hooks; | ||
|
||
compilation.tap(plugin, (compilation, { normalModuleFactory }) => { | ||
const { createParser, createGenerator } = normalModuleFactory.hooks; | ||
|
||
createParser.for("html/experimental").tap(plugin, () => { | ||
return new HTMLParser(); | ||
}); | ||
|
||
createGenerator.for("html/experimental").tap(plugin, () => { | ||
return new HTMLGenerator(); | ||
}); | ||
|
||
const { chunkTemplate } = compilation; | ||
|
||
chunkTemplate.hooks.renderManifest.tap(plugin, (result, options) => { | ||
const chunk = options.chunk; | ||
const output = options.outputOptions; | ||
|
||
const { moduleTemplates, dependencyTemplates } = options; | ||
|
||
for(const module of chunk.modulesIterable) { | ||
if(module.type && module.type.startsWith("html")) { | ||
const filenameTemplate = output.HTMLModuleFilename; | ||
|
||
result.push({ | ||
render: () => this.renderHTML( | ||
chunkTemplate, | ||
chunk, | ||
moduleTemplates.html, | ||
dependencyTemplates | ||
), | ||
filenameTemplate, | ||
pathOptions: { | ||
module | ||
}, | ||
identifier: `HTMLModule ${module.id}`, | ||
hash: module.hash | ||
}); | ||
} | ||
} | ||
|
||
return result; | ||
}); | ||
}); | ||
} | ||
|
||
renderHTMLModules(module, moduleTemplate, dependencyTemplates) { | ||
return moduleTemplate.render(module, dependencyTemplates, {}); | ||
} | ||
|
||
renderHTML(chunkTemplate, chunk, moduleTemplate, dependencyTemplates) { | ||
const { modules, /* render */ } = chunkTemplate.hooks; | ||
|
||
const sources = Template.renderHTMLChunk( | ||
chunk, | ||
module => module.type.startsWith("html"), | ||
moduleTemplate, | ||
dependencyTemplates | ||
); | ||
|
||
const core = modules.call( | ||
sources, | ||
chunk, | ||
moduleTemplate, | ||
dependencyTemplates | ||
); | ||
|
||
// let source = render.call( | ||
// core, | ||
// chunk, | ||
// moduleTemplate, | ||
// dependencyTemplates | ||
// ); | ||
|
||
chunk.rendered = true; | ||
|
||
return new ConcatSource(core); | ||
} | ||
} | ||
|
||
module.exports = HTMLModulesPlugin; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
const posthtml = require("posthtml"); | ||
const { | ||
imports, | ||
urls | ||
} = require("@posthtml/esm"); | ||
|
||
const { | ||
HTMLURLDependency, | ||
HTMLImportDependency, | ||
HTMLExportDependency | ||
} = require("./dependencies"); | ||
|
||
const { | ||
OriginalSource | ||
} = require("webpack-sources"); | ||
|
||
const isDependency = (msg) => { | ||
return msg.type.includes("import") || msg.type.includes("export"); | ||
}; | ||
|
||
class HTMLParser { | ||
constructor(options = {}) { | ||
this.options = options; | ||
} | ||
|
||
parse(source, state, cb) { | ||
const plugins = [ | ||
urls({ url: true }), | ||
imports({ imports: true }) | ||
]; | ||
|
||
const options = { | ||
to: state.module.resource, | ||
from: state.module.resource | ||
}; | ||
|
||
posthtml(plugins) | ||
.process(source, options) | ||
.then(({ tree, html, messages }) => { | ||
state.module._ast = tree; | ||
state.module._source = new OriginalSource(html); | ||
|
||
const dependencies = messages.filter(isDependency); | ||
|
||
// HACK PostHTML Bug (#250) | ||
messages.length = 0; | ||
|
||
return dependencies | ||
.reduce((done, dep) => new Promise((resolve, reject) => { | ||
if(dep.name.includes("HTML__URL")) { | ||
const dependency = new HTMLURLDependency(dep.url, dep.name); | ||
|
||
state.module.addDependency(dependency, (err) => { | ||
if(err) reject(err); | ||
|
||
resolve(); | ||
}); | ||
} | ||
|
||
if(dep.name.includes("HTML__IMPORT")) { | ||
const dependency = new HTMLImportDependency(dep.url, dep.name); | ||
|
||
state.module.addDependency(dependency, (err) => { | ||
if(err) reject(err); | ||
|
||
resolve(); | ||
}); | ||
} | ||
|
||
if(dep.name.includes("HTML__EXPORT")) { | ||
const dependency = new HTMLExportDependency(dep.export(), dep.name); | ||
|
||
state.module.addDependency(dependency, (err) => { | ||
if(err) reject(err); | ||
|
||
resolve(); | ||
}); | ||
} | ||
|
||
resolve(); | ||
}), Promise.resolve()); | ||
}) | ||
.then(() => cb(null, state)) | ||
.catch((err) => cb(err)); | ||
} | ||
} | ||
|
||
module.exports = HTMLParser; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
const { | ||
RawSource | ||
} = require("webpack-sources"); | ||
|
||
class HTMLModulesTemplatePlugin { | ||
constructor() { | ||
this.pluginName = "HTMLModulesTemplatePlugin"; | ||
} | ||
|
||
apply(moduleTemplate) { | ||
const { | ||
content, | ||
hash | ||
} = moduleTemplate.hooks; | ||
|
||
content.tap(this.pluginName, (source, module, { | ||
chunk | ||
}) => { | ||
if(module.type && module.type.startsWith("html")) { | ||
const html = new RawSource(source); | ||
|
||
return html; | ||
} else { | ||
return source; | ||
} | ||
}); | ||
|
||
hash.tap(this.pluginName, (hash) => { | ||
hash.update(this.pluginName); | ||
hash.update("1"); | ||
}); | ||
} | ||
} | ||
|
||
module.exports = HTMLModulesTemplatePlugin; |
Oops, something went wrong.