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

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.

Related

How to prevent module from being loaded in production in NodeJS?

As per question title, I have a module that should be used only in test, how can I prevent it from being used in production?
Looks like you are trying to mock some modules in NodeJS for test cases.
Instead of importing conditionally, a better way would be to export real or mock object conditionally.
import mockModule from './mockModule';
import realModule from './realModule';
const exported = (CONDITION) ? mockModule : realModule;
export default exported;
Also, instead of mockModule you may wish to export some empty object for your use case. Something like:
const exported = (CONDITION)? {} : realModule;
CONDITION to check if the test is running could be different based on some environment variable or your test suite. Eg for mocha you can use:
var isInTest = typeof global.it === 'function';
Source: How to detect if a mocha test is running in node.js?
Also, with require you can import modules conditionally:
if (CONDITION) {
const foo = require('foo');
}
It will be all down to your build process and environment variables. I know for example that if you build using Wepback then in your webpack.config file you have the following code which you can add an exclusion to:
module: {
rules: [
{ test: /\.ts$/, loader: "ts-loader", exclude: /*myModuleToExclude*/, },
]
}
Just look for the specific implementation for your specific build process.
Instead of adding in "dependencies", add module in "devDependencies" section of package.json

Type hints of flow not stripped by babel

I have a React.JS project which uses a custom 'theme' with UI components.
This theme also provides build scripts (webpack config, babel configs, etc.).
I want to start using Flow in this project.
I installed the needed npm packages and added flow to babel's presets, then I added props = {mytestprop: string} to one of my React` classes.
Webpack compiled my code successfully, but the type hints were not stripped! Of course, the browser was not able to execute this code - when I try to run it, it raisesReferenceError: string is not defined.
The current list of presets from .babelrc is: ["es2015", "react", "stage-2", "flow"]. I'm sure that this is the actual list used by babel because if I delete any of the first 3 presets, compilation fails.
Do you have any ideas on what could lead to this behavior when stripping Flow types?
It's not that type annotations are not being stripped. It's that { mytestprop: string } is not a valid type annotation on the right-hand side of an assignment because it clashes with the syntax for defining an object.
Specifically, when Flow's parser sees the statement { mytestprop: string } it will interpret this as an attempt to create an object with a field named mytestprop with its value set to the value of the variable string, so it will leave the statement alone as it is, and you'll get the error you've seen in the browser.
The correct way to type object declarations is to type the left-hand side of the declaration.
For instance,
let myProps: { myTestProp: string } = { myTestProp: "testProp" };
if you aren't declaring your props separately, you could declare a custom type:
type myPropType = { myTestProp: string }
// ...
const myComponent = (props: myPropType) => //render your component
Since the type statement is exclusive to Flow and not a valid JavaScript statement, it will be stripped correctly.

node ejs reference error data not defined at eval when handing data to view

i've been closing in on a node application using express and ejs, but when i try to hand data to my view from the controller like so
var myData = {
theData: data
};
res.render(path.join(__dirname + '/../views/index'), myData);
i get a nice error
ReferenceError:.. myData is not defined eval (from ejs lib)
when trying to access myData in the view like so
var data = <%-myData%>;
or in any other way basically, i've tried stringifying the data, wrapping it in another object and stuff like that but it still just won't show up, i have the feeling i'm missing something really basic here, does anyone have an idea on how to fix this?
The second argument you pass to render() is an object containing the view variables you want to use in your template. So the error you are seeing makes sense. If you want to use myData in that way you'd have to do something like this in your controller/app:
res.render(..., { myData: JSON.stringify(myData) });
There's a silly mistake I make when I try to send data from the server.
Here's the mistake:
var data = <%=myData%>;
What you should do when passing it:
var data = <%-myData%>;
It's supposed to be a dash NOT an equal before the variable name.
If your are generating the template with the HtmlWebpackPlugin plugin, the data should be passed in your webpack configuration file, along with the templateParameters property.
For example:
...
plugins: [
new HtmlWebpackPlugin({
filename: __dirname + "/src/views/index.ejs",
template: "./src/views/index_template.ejs",
templateParameters: {
myData,
},
}),
],
...

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 */
});

Having trouble defining global var in require.js

I'm trying to define a global object that i can reference across all of my modules. however, in the modules, i am unable to reference my path, and it's saying that "g" does not exist.
In main1.js, i have this:
requirejs.config({
paths: {
Underscore: 'lib/underscore/1.3.3/underscore.min',
Backbone: 'lib/backbone/0.9.2/backbone.min',
Globals: 'lib/backbone/ globalVars'
}
});
require([ 'views/pages', 'views/filters'], function(allPages, filters) {
filters.render();
allPages.render();
});
inside globalVars.js, i have this:
(function() {
var Globals = {
isDemo: false
}
console.log('in globalvars') // this shows in my console
}).call(this);
and finally, inside of view/pages.js, i have this:
define([
'Globals',
'Underscore',
'Backbone'
], function(g, _, Backbone){
console.log(g.isDemo) //<-- returns "TypeError: g is undefined"
If i use a define inside my main1.js like this:
define( 'Globals', function() {
return {
isDemo: true
}
})
it works just fine. I haven't had much luck with trying to figure out why this is not working. I'd like to be able to just include a path to the globalVars rather than boilerplate pasting a define block in each and every module that needs it, since changing isDemo to false would require updating many other module pages (main2.js, main3.js, etc) as well. thanks!
Well, to start with, your globalVars.js is not in the module pattern, so requirejs doesn't know what you're trying to register as the module. If you change that file to use the pattern, like the define you added to main1.js, you should be all set. Is there a reason you aren't defining it as a module?

Resources