Is it possible to register file to bundle inside loader?
Let's say I have a own loader for .cmp.html
files and I require files like this:
require("component/index.cmp.html");
then I'd like my loader to require also "component/index.cmp.js" to bundle, so it will be parsed by all loaders that apply and will appear in final bundle.js output
Is it possible with loaders?
// Code so far, it search for <StaticComponent name="xyz">
tags in html file and then replace it with html content of xyz, last thing to do is to bundle also xyz.js
components/static/header/index.cmp.html
<div class="some-html-of-this-component">
</div>
components/static/header/index.cmp.js
// this file has to be required to whole bundle
loaders/static-component-loader.js - this loader needs html string as input, please read from bottom to top
const fs = require("fs");
const JSDOM = require("jsdom").JSDOM;
const readFile = function(path) {
this.addDependency(path);
return fs.readFileSync(path, 'utf8');
}
const getNodeAttrs = function(node) {
const attributes = {};
for ( const attr of node.attributes )
attributes[attr.nodeName] = attr.nodeValue;
return attributes;
}
const setNodeAttrs = function(node, attributes) {
node.setAttribute("data-cmpid", attributes.id);
node.setAttribute("data-cmpname", attributes.name);
node.setAttribute("class", `cmp cmpstatic cmpid-${attributes.id} ${attributes.class || ""}`.trim());
if ( attributes.style )
node.setAttribute("style", attributes.style);
}
const replaceNode = function(node) {
const nodeParent = node.parentElement;
const nodeAttributes = getNodeAttrs(node);
const componentPath = `${__dirname}/../src/components/static/${nodeAttributes.name}`;
const componentPathHtml = `${componentPath}/index.cmp.html`;
const componentPathJs = `${componentPath}/index.cmp.js`;
const componentContentHtml = readFile.call(this, componentPathHtml);
node.innerHTML = `<div>${componentContentHtml}</div>`;
const nNode = node.children[0];
nodeParent.replaceChild(nNode, node);
setNodeAttrs(nNode, nodeAttributes);
return nNode;
}
const processNode = function(targetNode) {
const nodes = targetNode.querySelectorAll("static-component");
for ( const node of nodes ) {
const newNode = replaceNode.call(this, node);
processNode.call(this, newNode);
}
}
module.exports = function StaticComponentLoader(content) {
const jsdom = new JSDOM(content);
processNode.call(this, jsdom.window.document.body);
return jsdom.serialize();
}
somehow I need to include file from path componentPathJs
into whole bundle and then find a way to require it in runtime
Yes, there is a loader that does just this (when it parses a file, it will also require
additional files). It's called baggage-loader: https://github.com/deepsweet/baggage-loader. It offers file name placeholders to use in its configuration, so that, for example, whenever xyz.js
is loaded, it will insert a require()
for xyz.scss
, or xyz.json
, etc., depending on your configuration.
If you take a look at the source code, it's actually pretty simple -- basically, the loader just adds a require()
to the code that it's loading and returns the result. If you don't want to use baggage-loader
, you could easily write your own custom loader that does something similar, all you need to do is prepend require('whatever')
, as a string, to the code the loader receives.
(disclaimer: I am technically a maintainer of baggage-loader
, thought it's been a while since I worked on it)