I'm building a meteor app, and I'd like to know if it's possible to do something along the lines of:
var pages = [
'home',
'contact',
'other'
];
for(var page in pages){
import `/path/${page}`;
}
It's a small thing, but It would make things much simpler when it scales up. The above code doesn't compile, because import doesn't allow for interpolation. I've looked into using require syntax, which compiles, but can't find the files if I use interpolation. I also tried using meteor's dynamic-imports package, but couldn't figure it out.
Unfortunately most (if not all) build engines do not support interpolated import paths. They perform a static analysis to determine loaded assets.
Even Meteor dynamic imports need static paths, the "dynamic" part is about when the loading actually takes place, but Meteor still needs to know the path in advance.
Related
I want to use javascripts dynamic import function.
However, when I specify a whole url to import I get an error:
Cannot find module 'https://....
tho I know the resource is available. Is import restricted to same-origin script files (therefor all modules start with ./)?
On the other hand, I can dynamically create a script element and set the source to anything, and when its loaded all its functions (not a module) are in the global scope.
I would like to have the benefits of both :) loading script from cross origins but keep them in module structure.
since there are 2 comments thanks to the tips I found it seemed to be a problem with how parcel bundles, imports...
I could not find a way how to do it with parcel 2.7.0.
So is there a way to load a module, from a script tag that I create, set the type as a module and the src, to what I need.
Something slightly nicer then: const importPromise = eval("import(scriptUri)") which actually does the job
I believe this may be due to a lot of bundlers not being able to run dynamic imports:
https://discourse.threejs.org/t/importing-three-dynamically/28751
https://medium.com/front-end-weekly/webpack-and-dynamic-imports-doing-it-right-72549ff49234
https://github.com/parcel-bundler/parcel/issues/112
https://github.com/rollup/rollup/issues/2463
How to dynamically import a module which name is defined by a param with rollupjs?
Well, the issue isn't the bundlers not supporting them, but the usage of them is somewhat confusing to many, evident by the amount of tickets open in the various repos.
There are a few work arounds, but I think you may need to post a detail setup for us to help.
For now, I'd suggest (if possible), using defined strings in if conditions to get started. It's not ideal, but you may find yourself going in circles otherwise. If you provide the exact urls, that may help, but this is a good example:
function localeDynamicImport (locale) {
if (lang === 'en') {
return import('./locales/en.js');
}
if (lang === 'zh') {
return import('./locales/zh.js');
}
}
Other options include:
Pure ES6 module without a bundler
<script type="module">
import * as THREE from 'https://cdn.skypack.dev/three#0.130.0'
</script>
Webpack magic comments:
import(/* webpackIgnore: true */ 'http://example.com/some-module/some-module.bundle.js').then(module => console.log(module.default));
I'm trying to load all the "modules" contained in a particular directory. All of these can be individually loaded like this:
import 'dir1/plugins/one'
import 'dir1/plugins/two'
import 'dir1/plugins/three'
I've tried using something that sounded close to what I wanted to do:
require.context('dir1/plugins', true, /index\.js/)
This seems to load the files, as I can see their contents in the entry point, but I'm unable to use their functions later in my code.
I'm thinking I'm using require.context incorrectly, or it's doing something totally different as I'm understanding it. My goal is to not be forced to include every single plugin individually, as I want to load them all without exception.
Any hints?
I've been looking to develop a method for loading modules and/or components into an AOT-compiled Angular 4 application and been stymied by a variety of solutions that never quite seem to get me where I want to be.
My requirements are as such:
My main application is AOT compiled, and has no knowledge of what it is loading until runtime, so I cannot specifically identify my dynamic module as an entry component at compile time (which is explicitly necessary for the 'dynamic' component loading example presented on Angular.io)
I'd ideally love to be able to pull the code from a back end database via a GET request, but I can survive it simply living in a folder alongside the compiled site.
I'm using Webpack to compile my main application, breaking it into chunks - and so a lot of the SystemJS based solutions seem like dead ends - based on my current research, I could be wrong about this.
I don't need to know or have access to any components of my main application directly - in essence, I'd be loading one angular app into another, with the dynamically loaded module only perhaps having a few tightly controlled explicit interface points with the parent application.
I've explored using tools like SystemJsNgModuleLoader - which seems to require that I have the Angular compiler present, which I'm happy to do if AOT somehow allowed me to include it even if I'm not using it elsewhere. I've also looked into directly compiling my dynamic module using ngc and loading the resulting ngfactory and compiled component/module, but I'm not clear if this is at all possible or if so - what tools Angular makes available to do so. I have also seen references to ANALYZE_FOR_ENTRY_COMPONENTS - but can't clearly dig up what the limitations of this are, as first analysis indicates its not quite what I'm looking for either.
I had assumed I might be able to define a common interface and then simply make a get request to bring my dynamic component into my application - but Angular seems painfully allergic to anything I try to do short of stepping outside of it alltogether and trying to attach non-angular code to the DOM directly.
Is what I'm trying to do even possible? Does Angular 2+ simply despise this kind of on the fly modification of its internal application architecture?
I think I found an article that describes exactly what you are trying to do. In short you need to take over the bootstrap lifecycle.
The magic is in this snippet here.
import {AComponentNgFactory, BComponentNgFactory} from './components.ngfactory.ts';
#NgModule({
imports: [BrowserModule],
declarations: [AComponent, BComponent]
})
export class AppModule {
ngDoBootstrap(app) {
fetch('url/to/fetch/component/name')
.then((name)=>{ this.bootstrapRootComponent(app, name)});
}
bootstrapRootComponent(app, name) {
const options = {
'a-comp': AComponentNgFactory,
'b-comp': BComponentNgFactory
};
https://blog.angularindepth.com/how-to-manually-bootstrap-an-angular-application-9a36ccf86429
I'm trying to load multiple modules on the fly via chokidar (watchdog) using Meteor 1.6 beta, however after doing extensive research on the matter I just can't seem to get it to work.
From what I gather require by design will not take in anything other than static strings, i.e.
require("test/string/here")
Since if I try:
var path = "test/string/here"
require(path)
I just get Error: Cannot find module, even though the strings are identical.
Now the thing is I'm uncertain how to go on about this, am I really forced to either use import or static strings when using meteor or is there some workaround this?
watchdog(cmddir, (dir) => {
match = "." + regex_cmd.exec(dir);
match = dir;
loader.emit("loadcommand", match)
});
loader.on('loadcommand', (file) => {
require(file);
});
There is something intrinsically weird in what you describe.
chokidar is used to watch actual files and folders.
But Meteor compiles and bundles your code, resulting in an app folder after build that is totally different from your project structure.
Although Meteor now supports dynamic imports, the mechanism is internal to Meteor and does not rely on your actual project files, but on Meteor built ones.
If you want to dynamically require files like in Node, including with dynamically generated module path, you should avoid import and require statements, which are automatically replaced by Meteor built-in import mechanism. Instead you would have to make up your own loading function, taking care of the fact that your app built folder is different from your project folder.
That may work for example if your server is watching files and/or folders in a static location, different from where your app will be running.
In the end, I feel this is a sort of XY problem: you have not described your objective in the first place, and the above issue is trying to solve a weird solution that does not seem to fit how Meteor works, hence which may not be the most appropriate solution for your implicit objective.
#Sashko does a great job of explaining Meteor's dynamic imports here. There are also docs
A dynamic import is a function that returns a promise instead of just importing statically at build time. Example:
import('./component').then((MyComponent) => {
render(MyComponent);
});
The promise runs once the module has been loaded. If you try to load the module repeatedly then it only gets loaded once and is immediately available on subsequent requests.
afaict you can use a variable for the string to import.
Does using the JavaScript import statement for images, css and others defeat the purpose of import statement which was designed to import only the JS Modules ?
Of course, for now it gets transpiled to ES5 require using webpack. But that same question comes up again. Is it incorrect to use import statement to import images or css or files ?
EDIT:
I like the idea of controlling imports that we can control the assets on build time in such a clean way - The idea that I use the image path to import the image, and
on different environments the image path would contain different values - url or path
this image can be compressed on build time
the JS module importing this image can contain the image dimensions through a custom loader
assets dependency tree is maintained at one place and un-imported items gets chucked away automatically
rebuild time is fast - DX(developer experience) would be good
I guess, this is much better than using any templating, using placeholders in the JS files to inject URLs or paths based on environment during pre-build (webpack).
But using the import statement feels not right to do so in terms of principle or semantics.
This is from Mozilla Developer Network:
The import statement is used to import functions that have been exported from an external module, another script, etc.
From everything I've read on MDN and other sources its purpose is to make a module/script methods and properties available within the current scope it's being imported into.