How to dynamically load and initialize a module with webpack - javascript

Here is the setup of a website I'm working on:
I have multiple types of pages. Each page have a (known) number of js views(components), encapsulated in modules. For each page type I create its own entry point. Previously I used RequireJS and rjs for bundling, so I had a special module (called 'loader'), which could load and initialize each view.
So basically, I have such a structure
-news.js
-homepage.js
-components
|
-header.js
-menu.js
-search.js
-article.js
-loader.js
and my news.js is
require('components/header');
require('components/search');
require('components/article');
var loader = require('components/loader');
loader.initAll();
and my homepage.js is
require('components/header');
require('components/search');
require('components/menu');
var loader = require('components/loader');
loader.initAll();
Each component looks like
<div class="js-component" data-component="components/article"></div>
And inside loader.js I would like to see something like
module.exports = {
initAll: function () {
// get all components on the page
var components = document.querySelectorAll('.js-component');
components.forEach(function(component) {
component.name = component.getAttribute('data-component');
// next is obviously not working with webpack, but is what I need
require(component.name).init();
})
}
}
How should I organize this with webpack?

Related

Webpack loader for file, subfiles and add them to tracking list

I have the map+tilemap project created in a 3rd-party app. The whole project is a set of files, the main file (XML) representing the 2D game level map and some other files (subfiles) representing graphics and tilemaps.
I am trying to create a Webpack Loader that will compile and convert the whole map/tilemap project into JSON object, that is comfortable to use in javascript. And I still can't get how to:
How can I access subfiles (taken from relative paths from the main file), what is the way to access the current directory (where the main file is placed), and the name of the main file?
How can I explain to Webpack to track changes in all subfiles, so it will run the loader again automatically to compile the whole map/tilemap project (partial re-packing).
I spent 2 days to find any working solutions, it is possible at all?
Thanks a lot!
For the first question, webpack loader is expose the file info by this, you can do like this:
module.exports = function (source) {
const loaderContext = this;
const { sourceMap, rootContext, resourcePath } = loaderContext;
const sourceRoot = path.dirname(path.relative(context, resourcePath));
...
}
For the second question, i think that maybe you can use the module.hot to track the subfiles change, like this:
if (module.hot) {
module.hot.accept('filepath', ()=>{
...
})
}

NodeJS Module Exports with Additional Required Files

I am trying to break my nodejs code up into as small of files as possible to keep things modular. I have an app.js that is needing to use another method that I have moved to utils.js. The utils file however has a method that has a requirement for another library.
Should my utils.js file be "requiring" dependencies or should all those go in my app.js?
// app.js
var utilities = require('./utilities');
..
return utilities.anotherMethod();
// utils.js
module.exports = {
producer: function () {
// Handle mapping of fields depending on the source system
return 'map fields'
},
anotherMethod: function () {
// I require another lib. Do I do that here or app.js?
var kafka = require('kafka-node');
}
};
Update: Regarding the close request for an opinion based answer is essentially telling me that this can be done either way, which is what I was trying to clarify.

Webpack 4 bundles or ignores dynamic imports

I'm using dynamic imports in index.js:
import('./componentA');
import('./componentB');
import('./componentC');
const myIndexVar = 'My Index Var';
index.ts is the entry point in my webpack.config.js.
The result is a single bundle containing all 4 files - index and the 3 components.
My goal is to have each of the files separately in my dist folder, so that index can load the components dynamically on demand at runtime.
i.e. at runtime I'd like to load index.js, and in turn it'll request components a-c via dynamic imports when needed.
Depending on events yields the same results:
document.body.onclick = () => import('./componentA');
If I try something like this it completely ignores the component and doesn't add it in any way to the dist folder:
let componentName = './componentA';
import(componentName);
I tried following this article:
https://webpack.js.org/guides/code-splitting/
Am I misunderstanding what's supposed to happen?
If I'm not on the right track, is there any alternative that can help me reach my goal?

Compile and inject a page to ionic app on runtime

I have a project that I need to add an Ionic Page Component from remote server on runtime. Firstly, I need to transpile the component from typescript before and deploy to a server. After that, on a button click event, I need to download the component and register that as ionic page. It would be very helpful if I can get help in generation of js from typescript file. The main problem on js generation is, I'm using webpack and webpack is changing all the imports into its own function calls and it contains random(?) numbers in it.
Second problem is that I can't get and register a page in runtime. I'm using lazy loading but couldn't find a way to register that page. I tried the following code but didn't work:
let injector = ReflectiveInjector
.fromResolvedProviders([], this.vcRef.parentInjector);
// 1. Create module loader
let loader = new SystemJsNgModuleLoader(this.compiler);
loader.load("http://example-website.com/test-module")
.then((nmf:NgModuleFactory<any>) => {
// 2. create NgModuleRef
let ngmRef = nmf.create(injector);
let page = ngmRef.instance.page;
// 3. Create component factory
let cmpFactory = ngmRef
.componentFactoryResolver
.resolveComponentFactory(page);
// 4. Create the component
let componentRef = this.span.createComponent(cmpFactory, 0, injector,[]);
// 5. Init the component name field.
componentRef.instance.name = "TestPage";
// 6. Refresh the component area.
componentRef.changeDetectorRef.detectChanges();
componentRef.onDestroy(()=> {
componentRef.changeDetectorRef.detach();
});
});
I'm using ionic 3, angular 5 with typescript 2.4.2.

How to require javascript model files within the index.js file?

I have 2 model files containing a constructor in each, and an index.js file, that I wish to use to insert elements into a HTML file, using innerHTML. I want to use one of the variables from the js model file, however when I try to require the files in the index.js file, the innerHTML file suddenly stops working. Please note, the code in the current `window.onload' function is inserting h1 elements as a test, I will be replacing this with a return value from the constructor, but at the moment, when I require the files, even the h1 insert stops working. Code snippets that I think are relevant can be seen below:
index.js file:
var ToDo = require('../src/toDo.js');
var ToDoList = require('../src/toDoList.js');
window.onload = function() {
// create a couple of elements in an otherwise empty HTML page
var heading = document.createElement("h1");
var heading_text = document.createTextNode("Big Head!");
heading.appendChild(heading_text);
document.body.appendChild(heading);
}
Model file 1:
function ToDo(task) {
this.task = task;
this.complete = false;
}
module.exports = ToDo;
function ToDoList() {
this.array = [];
}
ToDoList.prototype.add = function(task) {
this.array.push(task);
};
ToDoList.prototype.popTask = function() {
var poppedTask = this.array.pop();
var concat = "<ul><li>";
var concat2 = "</li></ul>";
return (concat + poppedTask.task + concat2);
};
module.exports = ToDoList;
require is CommonJs feature, and it's not supported by browsers without this library. So you would need to use it in your project if you want modules with require syntax.
Update
To use require feature, you would need some module loader. There are two very popular that you could check out - Webpack or Browserify. They both support CommonJS require that you are looking for. As for me, I like webpack most, cause it is very powerful out of the box.
To read about their comparison :
https://medium.com/#housecor/browserify-vs-webpack-b3d7ca08a0a9#.lb3sscovr
RequireJS is another module loader, but he works not with CommonJs-style modules (require). He implements AMD-style modules.
You can check this article to understand how AMD is different from CommonJS:
https://auth0.com/blog/2016/03/15/javascript-module-systems-showdown/

Categories