Is there a way to compile directory of templates and store in array object using Webpack?
Explanation: I am now using list of handlebars templates. I precompile the list of templates using handlebars compiler in gulp.
gulp.src('client/src/templates/**/*.hbs')
.pipe(gulp_handlebars({
handlebars: handlebars,
compilerOptions:{
knownHelpers: helpers,
knownHelpersOnly:true}
}))
.pipe(wrap('Handlebars.template(<%= contents %>)'))
.pipe(declare({
namespace: 'appname.templates',
noRedeclare: true,
processName: function(filePath) {
return declare.processNameByPath(filePath.replace('client/src/templates/', ''));
}
}));
I would then access templates through appname.templates array. It was working fine.
Now, I am moving to Webpack. If I use the handlebars-loader ,
it allows me to require every template by name like
var template = require("./file.handlebars");
Is there a way to get all templates in one directory as an array like
var templates = require("./*.handlebars");
I usually would go to the folder you have your templates and have an templates/index.js file such as:
export templateA from './templateA.handlebars'
export templateB from './templateB.handlebars'
export templateC from './templateC.handlebars'
...
Then you can do:
import * as templates from './templates'
And templates is an object that holds all your templates. You can also do templates.templateA to access them by name.
Related
The code environment is browser. bundle tool is webpack. I have a router.js file like:
import foo from './views/foo.vue'
import bar from './views/bar.vue'
import zoo from './views/zoo.vue'
//use foo, bar, zoo variables
I've many '.vue' files to import like this under views folder. Is there a programmatical way to auto import all [name].vue as local variable [name]? So when I add or remove a vue file in views, I don't need to manually edit router.js file. this one seems a little dirty.
for (let name of ['foo', 'bar', 'zoo']) {
global[name] = require(`./views/${name}.vue`)
}
Nope, that's it. You have a choice between dynamic import and automation, or explicit coding and type-checking / linting.
Unfortunately, it's one or the other. The only other way to do it is meta-programming, where you write code to write your code.
So you generate the import statements in a loop like that, and write the string into the source file, and use delimiting comment blocks in the source file to identify and update it.
The following works for me with webpack and vue.
I actually use it for vuex and namespaces. Hope it helps you as well.
// imports all .vue files from the views folder (first parameter is the path to your views)
const requireModule = require.context('./views', false, /\.vue$/);
// create empty modules object
const modules = {};
// travers through your imports
requireModule.keys().forEach(item => {
// replace extension with nothing
const moduleName = item.replace(/(\.\/|\.vue)/g, '');
// add item to modules object
modules[moduleName] = requireModule(item).default;
});
//export modules object
export default modules;
I have noticed that when I am importing source in the old way, like this: require('./my-script') it injects the code of the script into the main bundle.js.
And when I am importing like this: import('./my-script')
it created a separate new file and I even can name it with:
import(/* name.js */ './my-script');
That is nice, but in the new way of using import instead of require - how can I send parameters to the imported function?
For example, in require I could do require('./my-script')('something');
However this cannot be achieved using import
How can I pass parameters to an imported function and make it as a separate chunk in webpack?
This is the my-script.js (for example only):
// my-script.js
module.exports = str => {
return `${str} was returned`;
}
import(name) is used for code splitting (creating separate chunks) and will return a promise for the module's exports once the chunk has been retrieved asynchronously.
With your example, it can be used with something like the following:
import('./my-script').then(myScript => myScript.default('hello'))
The Dynamic imports section provides a more complete example and describes how import() is used for code splitting and here in Magic Comments are options listed which you can use to control how the chunk is created and when it's retrieved so you can tweak the user experience.
I registered it
handlebars.registerPartial('nav', 'view/partials/nav');
And I called it
{{> "nav"}}
but I only get this
view/partials/nav
According to documentation arguments of .registerPartial(arg1, arg2) are:
Partial name
Partial content
Handlebars does not have built in functionality to serve static files from relative paths.
So without using external framework like for example the one hapijs uses to render views, what you can do is:
Handlebars.registerPartial('nav',
('<nav>' +
// your <nav> html
// ...
// ...
</nav>')
);
I'm building a new application using Marionette and RequireJS, and I've got the following structure:
/main.js -- Main require() call that includes app.js and calls Application.start()
/app.js -- Application definition
/modules
/sub
/controller.js -- Defines a sub-application, requires app.js
...
I'm trying to keep dependencies at the top level of each file, as opposed to using require() inline, so that the r.js compiler can find them. The problem is, in my controller.js file, I am requiring app.js (in order to add initializers) and so I cannot require controller.js in app.js until after the Application has initialized, which means I can't put controller in the top-level define() array.
A simplified example of the currently working code:
// app.js
define(['marionette'], function(Marionette) {
var Application = new Marionette.Application();
Application.on("initialize:after", function() {
require(['modules/sub/controller'], function() {
Backbone.history.start();
});
});
});
// controller.js
define(['app'], function(Application) {
Application.module('SubApplication', function(SubApplication, Application, Backbone, Marionette, $, _) {
var router = Marionette.AppRouter.extend({
appRoutes: { "foo": "bar" }
});
var controller = { foo: function() {} };
Application.addInitializer(function() {
new router({ controller: controller });
});
});
});
I'm still fairly new to both Require and Marionette, so any suggestions would be welcome! I do know that I can include the files I want via the include option to r.js, but I thought this question was worth asking nonetheless.
The way I've chosen to do it in my book on Marionette and RequireJS is to require inline the modules that are only necessary for a subset of functionality. This simplifies development, and also means that modules won't be loaded unless that code path is triggered.
R.js will find inline dependencies just fine (provided they're defined as strings, i.e. not computed dynamically). In addition, they will also work with Almond.js (but don't forget to use the findNestedDependencies option in your build file).
Hope this helps!
I'm using backbone with requireJS and I have several template files, I would like to use require() to load the templates without passing it in the module definition, for instance inside a login function in the view, I'd want to do somethign like
var html = require( ['text!templates/users/login_form.html'] );
Did you download the RequireJS text plugin? You need to download it and it put it your project before RequireJS can use text resources as dependencies. You can read about it here on the project page and also in their API documentation.
Yes you can!
loginTemplate = require(['text!templates/users/login_form.html'],
function(Template) {
return Template;
});
this should help you :-)
You can do that asking for "require" as a dependency in the module definition
define(["require", "other_dependencies"], function(require, etc) {
var template = require('text!templates/users/login_form.html');
});