Webpack Config - Pass [hash] to loader data - node.js

Im using the pug-html-loader to load a large number of pug templates and convert them to html in the build directory. this is working fine, but I want to be able to insert the webpack hash in the pug templates.
I cant work out how to set up my webpack.config to pass this data to the pug-html-loader
This is the loader in my webpack.config
{
loader: "pug-html-loader",
options: {
exports: false,
pretty: PRODUCTION ? false : true,
data: { hash: WEBPACK HASH HERE }
}
}
As you can see I want to insert the webpack hash in the data object where I have WEBPACK HASH HERE currently, but cant work out how to access/pass that in the webpack.config file

Related

How to use a custom Webpack Loader in Gatsby JS?

I am trying to change the default webpack loader for SVG files in Gatsby JS. I want to use the 'svg-url-loader' instead of the default 'url-loader'. I have installed it, and it works fine with webpack-inline-loaders.
But to avoid repeating the process, I decided to use the onCreateWebpackConfig Node API to change the loader for the SVG files. So I added the below code in the gatsby-node.js file.
exports.onCreateWebpackConfig = ({
stage,
getConfig,
rules,
loaders,
plugins,
actions,
}) => {
actions.setWebpackConfig({
module: {
rules: [
{
test: /\.svg/,
use: {
loader: "svg-url-loader",
options: {
limit: 4096,
iesafe: true,
},
},
},
],
},
});
};
But the website is now not displaying any SVG image but alt text. This is because the src attributes of those IMG tags are using a faulty base64 encoded image and not the UTF8 encoded SVG XML tag.
The console is not logging any errors. I have also tried creating a local plugin at the /plugins dir, but it doesn't work. I am developing my site on my local machine and building it using Gatsby Cloud. The problem exists in both places.
Here's the link to a minimal repro.
The problem here is that to use a custom loader in any framework, you have to disable the default loader first. Then you'll be able to add your custom loader. So, first, you have to disable the default, 'url-loader' and then set the 'svg-url-loader' for SVG files.
exports.onCreateWebpackConfig = ({
stage,
getConfig,
rules,
loaders,
plugins,
actions,
}) => {
const config = getConfig();
config.module.rules.find(
(rule) =>
rule.test &&
rule.test.toString() ===
"/\\.(ico|svg|jpg|jpeg|png|gif|webp|avif)(\\?.*)?$/"
).test = /\.(ico|jpg|jpeg|png|gif|webp|avif)(\?.*)?$/;
config.module.rules.push({
test: /\.svg/,
use: {
loader: "svg-url-loader",
options: {
limit: 4096,
iesafe: true,
},
},
});
actions.replaceWebpackConfig(config);
};

How to skip a define getting included at the end of the bundle, When combining non-amd script files using requirejs optimizer r.js?

I'm trying to optimize my javascript project with r.js optimizer from requirejs. I use both amd and non-amd modules in my project. There will be two environments, one with requirejs environment and the other with no requirejs environment.The files at the non-requirejs environment should not have on require or define calls. While combining amd-modules into bundles using r.js it is fine to have a define call with bundle name at the end of the file. But for the non-requirejs environment after the files have been optimized, they are also getting a define insertion at the end of the file with the module name.
Let's take I have four files A and B which are AMD-modules and C and D are non-AMD modules.
my build.js is like this
({
appDir: "../",
baseUrl: "./",
dir : "../../../output",
paths: {
A : '../somepath/to/A',
B : '../somepath/to/B'
},
modules : [
{
name : 'bundle1',
create : true,
include : ['A', 'B']
},
{
name : 'bundle2',
create : true,
include : ['C', 'D']
}
],
// removeCombined : true,
cjsTranslate: false,
optimizeCss : "none",
skipModuleInsertion: true,
optimize: "uglify",
fileExclusionRegExp: /^(((r|app.build)\.js)|(v0))$/,
keepBuildDir: false,
bundlesConfigOutFile: "bundles.js",
onModuleBundleComplete : function(data) {
console.log(data)
}
})
This is the bundles amd-file looks like.
define('A', function(){
//some stuff of A
});
define('B', function(){
//some stuff of B
});
define('bundle1',function(){});
The bundled non-amd file looks like
//some stuff of C
});
//some stuff of D
define('bundle2',function(){});
How to resolve this situation. I have gone through the optimization docs and example.build.js. still couldn't figure out the way. Am I missing something ? Is there a way to exclude that define call at the end of the non-amd-modules. If yes, How ?
I see you have used skipModuleInsertion option which based on the documentation should have helped you. I am not sure why it didn't.
Another option you can use is after the build is complete before writing to file, you can remove that particular define call using onBuildWrite

What exactly am I supposed to do with "module.exports = 'html_template_content'" on webpack

So I want to do a very simple task using webpack.
I have a few static HTML templates like e.g.
test.html
<div><span>template content</span></div>
and all I want to do is return the string inside the template
e.g
require("raw!./test.html")
with should return a string like:
"<div><span>template content</span></div>"
but instead, it returns the following string
"modules.exports = <div><span>template content</span></div>"
I have tried several modules, like the raw-loader and html-loader.
and they both behave the same way.So I took a look at the source code, just to find out that its SUPPOSED to behave this way.
so what exactly am I expected to do with this, if I just want the raw
HTML? is it a bad practice just to remove the prepended
"module.exports =" string? from the bundle
edit: removing the 'modules.export =' part results in the bundle returning nothing :/
my config
module.exports =
{
module:
{
loaders:
[
{ test: /\.html$/, loader: "raw-loader" }
]
}
};
The solution is to require your file without specifying any additional loader, as this is already specified in the webpack config
const test = require('./test.html')
Explanation: With your current code, you are applying the raw loader twice to your file. When you specify a loader chain in your configuration:
loaders:
[
{ test: /\.html$/, loader: "raw-loader" }
]
... you are already telling webpack to add this loader to the loader chain every time you require a file matching the test condition (here, every html file)
Therefore, when you write this
const test = require('raw!./test.html')
... it is actually equivalent to this
const test = require('raw!raw!./test.html')
I finally figured it out I think. You need to resolve the path name using require.resolve(./test.html) https://nodejs.org/dist/latest-v7.x/docs/api/globals.html#globals_require
When you write require('./test.html') it means that you simply run the code returned by the loaders chain. The result is exported in this code as module.exports. To use this result you need to assign your require statement to variable:
var htmlString = require('raw!./test.html');
//htmlString === "<div><span>template content</span></div>"
Remember that any loader in Webpack returns JS code - not HTML, not CSS. You can use this code to get HTML, CSS and whatever.

How to run intern to test a dojo application running with node.js ?

I'm trying to use intern to test a dojo application running under node.js
My intern.js configuration file is something like:
define({
loader: {
packages: [
{ name: 'elenajs', location: 'lib' },
{ name: 'tests', location: 'tests' }
],
map: {
'elenajs': { dojo: 'node_modules/dojo' },
'tests': { dojo: 'node_modules/dojo' }
}
},
suites: [ 'tests/all' ]});
When I try to run a test with node node_modules/intern/client.js config=tests/intern, I get this error:
Error: node plugin failed to load because environment is not Node.js.
Normally I would have configured dojo with something like
dojoConfig = {
...
hasCache: {
"host-node": 1, // Ensure we "force" the loader into Node.js mode
"dom": 0 // Ensure that none of the code assumes we have a DOM
},
...
};
How can I solve this with intern?
The issue that you are experiencing is caused by the fact that there is code in Dojo that relies on certain has-rules being set from the Dojo loader, but this doesn’t happen because the Dojo loader isn’t in use. There are a couple of potential workarounds:
Since Intern’s loader sets some of the same rules, you can load intern/node_modules/dojo/has and run has.add('dojo-has-api', true) before anything else tries to load your dojo/has module. This should cause Dojo to use the has.js implementation from Intern’s loader (and adopt all the rules it already has set, which currently includes host-node). The best place to do this is going to be the Intern configuration file, which would end up being something like this:
define([ 'intern/dojo/has' ], function (has) {
has.add('dojo-has-api', true);
return {
// your existing Intern configuration object…
};
});
Before loading any modules that call has('host-node'), load dojo/has and intern/node_modules/dojo/has and call dojoHas.add('host-node', internHas('host-node')) (or I guess you can just hard code it :)). This would require a loader plugin to be used in place of your suites array:
// tests/preload.js
define({
load: function (id, require, callback) {
require([ 'dojo/has' ], function (has) {
has.add('host-node', true);
require(id.split(/\s*,\s*/), callback);
}
}
});
And then your suites would change to suites: [ 'tests/preload!tests/all,tests/foo,tests/bar' ].
Any other has-rules that Dojo code relies on that are set by the Dojo loader will need to be set yourself. Any other rules that Dojo adds from other parts of itself will work correctly.

Is there a more concise way of including dependencies in RequireJS

Suppose I have a module that starts like the following:
define(['jquery', 'actions', 'util', 'text!../templates/dialog.html!strip', 'text!../templates/requestRow.html!strip', 'text!../templates/respondForm.html!strip'], function($, actions, util, tDialog, tRequestRow, tRespondForm) {
This module contains most of the code for writing to my client UI. It also loads a couple other modules I've written as well as 3 HTML templates using the text.js plugin. I'm wondering if there's a more concise way of doing this? As the application grows, I may have additional templates to load, or modules and it just seems like my define statement could grow to be a bit ugly. Should I just add my template paths to require.config in my main.js like this:
require.config({
baseUrl: '/webrequests/resources/scripts/',
paths: {
'modernizr': '../js/vendor/modernizr-2.6.2-respond-1.1.0.min',
'bootstrap' : '../js/vendor/bootstrap.min',
'dialog' : 'text!../templates/dialog.html!strip',
'requestRow' : 'test!../templates/requestRow.html!strip',
'respondForm' : 'text!../templates/respondForm.html!strip'
}});
Is there perhaps some way to load all templates within a directory and just have 1 dependency to include in the define statement?
Thanks in advance.
You could make a module for loading in the templates you frequently use. So group the templates to be loaded in one module, that way you can just load this template module instead of the individual templates:
// generalTemplates.js
define([
'text!../templates/dialog.html!strip',
'text!../templates/requestRow.html!strip',
'text!../templates/respondForm.html!strip'
], function (tDialog, tRequestRow, tRespondForm) {
return {
dialog: tDialog,
requestRow: tRequestRow,
respondForm: tRespondForm
};
});
So that in your module, you can simply include the templates like any other module:
define([
'jquery',
'actions',
'util',
'generalTemplates'
], function($, actions, util, templates) {
var tDialog = templates.dialog,
tRequestRow = templates.requestRow,
tRespondForm = templates.respondForm;
/* You can do stuff with the templates here */
});

Resources