Automatically export everything from ES5 file to be used in ES6 - javascript

I have pretty straightforward ES6 code (init.js):
import App from '../vendor/app';
window.init = function() {
let app = new App();
app.hello(); // prints "hello" to console
}
app module (app.js) is ES5 one and I don't want to modify this file:
function App() {
}
App.prototype.hello = function() {
console.log('hello from vendor module');
}
The code above won't work, because I need to add
export default App;
to the end of app.js. But I want to keep vendor files clean and without any modification as much as it possible. The tricky part is that app.js is depending on other ES5 modules, for example:
App.prototype.hello2 = function() {
dialog.show('hello from vendor app module, but using another vendor "dialog" module');
}
dialog variable is defined in ES5 dialog.js.
It works well when you add script-tags to your html page. I also want to avoid that. Ideally, I want to modify init.js only. Use some sort of import, so it will attach all of the vendor modules automatically to my init.js.

Related

Importing / exporting Javascript Object Properties

I support a relatively complex legacy codebase, but am looking to modernise it a little by bringing in Webpack so that we'd have import & export capabilities in JS.
The problem I'm having is that we use a global object called App where we define and add different properties depending on the page. So for example we have the following file where we instantiate App (loaded on all pages):
app.js
const App = (() => {
const obj = {
Lib: {},
Util: {},
// etc
}
return obj;
})();
Then in another file we add to App.Lib just for the specific page that needs it:
lazyload.js
App.Lib.Lazyload = (() => {
// lazyload logic
})();
We simply concatenate the files during the bundling process, but obviously this is not ideal as none of the files have no knowledge of what goes on outside of it.
Exporting only seems to work for the top level object (where the object is defined), so anything I add to it elsewhere cannot be exported again. For example if I add export default App.Lib.Lazyload; at the end of lazyload.js and then try to import it elsewhere it will not import the Lazyload property.
Is there any way to get this to work without major refactor? If not, would you have any suggestions about the best way to handle it?
I don't think you can import Object.properties in JS. If you want to bundle specific packages (say Lazyload) for packages that need them, you might try:
//lazyload.js
export const LazyLoad = {
//lazyload logic
}
then somewhere else...
import {LazyLoad} from 'path/to/lazyload.js';
// assuming App has already been created/instantiated
App.Lib.Lazyload = LazyLoad;
Using Export Default...
//lazyload.js
const LazyLoad = {};
export default LazyLoad;
then...
import LazyLoad from 'path/to/lazyload.js';
App.Lib.LazyLoad = LazyLoad;
You can find help with Imports and Exports at MDN.

Scope import for an instance only

Good evening to everyone.
I'm not sure how can I explain my issue. I will show it to you by showing examples of the code and expected results. I could not use code from the real issue because the code is under license. I am very sorry for that and I will be glad of someone can help me solve my issue.
I'm using latest version of webpack, babel.
My application is spliced to three parts what are dynamically imported by each other. It is mean if I run split chunks plugin it will really create three clear files.
The parts are Core, Shared, Application. Where the Core only creating an instance of the application.
Result of the parts is bundled to single file. So it is linked by one html's script tag.
Project structure is:
src/app // For Application
src/core // For Core
src/shared // For Shared
In webpack configuration I am resolving alias for import ˙Editor$˙.
I renamed naming of variables because they are including project name.
resolve: {
alias: {
"Editor$": path.resolve('./src/app/statics/Editor.js'),
}
},
The content of Core file is
function createInstance(name, id) {
import("app").then(App => {
App(name, id)
});
}
The little bit of Application file is
imports...
import Framework from "./framework"
function createApp(name, id) {
new Framework({name, id}).$mount(...)
}
export default createApp
In the Application classes (what are instantiated inside Framework)
Is this import
import Editor from "Editor"
The Editor class is a singleton. But only for created instance.
class Editor {
static instance;
id = null;
constructor(){
if(this.constructor.instance){
return this.constructor.instance
}
this.constructor.instance = this
}
static get Instance() {
return this.instance || (this.instance = new this())
}
static get Id {
return this.Instance.id;
}
}
export default Editor
The issue is webpack dependency resolving. Because webpack puts and unify all imports to the top of the file.
So the imports are evaluated once through the life-cycle of the program.
But I need to tell webpack something like: There is an instance creation. Declare the new Editor singleton for this scope. Don not use the already cached one.
My another idea how to fix this is to set context for the instance. And in the Editor singleton create something like new Map<Context, Editor> if you get what I mean. But I did not find a way how to set a context for an instance or scope the import only for it.
I will appreciate any help. I am googling two days and still no have idea how to do it without rewriting all the imports.
Sorry for bugs in my English. I am not native speaker and my brain is not for languages.
Thanks everyone who take look into my issue.
How about recreating the Editor:
// Editor.js
class Editor {
// ...
}
let instance;
export function scope(cb) {
instance = new Editor();
cb();
instance = null;
}
export default function createEditor() {
if(!instance) throw Error("Editor created out of scope!");
return instance;
}
That way you can easily set up different scopes:
// index.js
import {scope} from "./editor";
scope(() => {
require("A");
require("B");
});
scope(() => {
require("C");
});
// A
import Editor from "./editor";
(new Editor()).sth = 1;
// B
import Editor from "./editor";
console.log((new Editor()).sth); // 1
// C
import Editor from "./editor";
console.log((new Editor()).sth); // undefined
// note that this will fail:
setTimeout(() => {
new Editor(); // error: Editor created out of scope
}, 0);
That also works for nested requires and imports as long as they are not dynamic.

Webpack global variable from multiple files

I'm trying to rewrite bunch of legacy JS files into module structure. I have obfuscated plugin which contains out of few files, which in turn work with single global variable. The order of execution of these files matters.
Example:
file1.js
var myModule = {someStuff};
file2.js
myModule.someProperty = someValue;
What i want to achieve is to import them all somehow and get this global variable myModule.
Possible implementation:
myModule.js
import myModule from "file1.js";
import myModule from "file2.js"; // ofc i know it does not work this way
export default class myProgramm {
constructor(){
myModule.run({options});
}
}
What i tried so far is webpack provide plugin (https://webpack.js.org/plugins/provide-plugin/), but it doesn't work with multiple files. Also i tried to use provide-multiple-plugin (adopted to webpack 4) from this gist :https://gist.github.com/shellscape/a7461022503f019598be93a512a1901a. But it seems to include files in nearly random order, so it can happen that myModule is not defined, while file2.js is executed first.

How does the JavaScript Import work under the hood?

How does the import statement actually work in JavaScript? I read the documentation and it says that it places exported code within the scope of the file. Does that mean that the code is copied over into the file where I type import?
For example - in library.js I have:
export {export function getUsefulContents(url, callback) {
getJSON(url, data => callback(JSON.parse(data)));
}
In main.js I have:
import { getUsefulContents} from 'library.js';
getUsefulContents('http://www.example.com',
data => { doSomethingUseful(data); });
This allows me to call getUsefulContents() in main.js. My question is, does main.js now have the contents that I exported from library.js?
Is using import the same as just having physically defined getUsefulContents() in main.js?
function getUsefulContents(url, callback) {
getJSON(url, data => callback(JSON.parse(data)));
}
getUsefulContents('http://www.example.com',
data => { doSomethingUseful(data); });
The main reason why I ask is because I want to know if using import will have an effect on main.js file size? Or is something else going on under the hood?
Thank you!
Depends on how you are using main.js. If you run it through a bundler, then the bundler will probably include library.js into main.js to pack it up into one file. In that case, the only advantage would be maintainability and ease of development because you are focused on the file you are working on. If you are simply running the import statement and deploying your application, the import statement won't affect the file size of main.js.
It just namespacing it within the file that you are importing it to so
any code from useful-library.js is included in the file, I visualize it this way
import { usefulCodeFromLibrary } from './useful-library.js';
((usefulCodeFromLibrary)=>{
// My excellent code
// Imported code doing it's job
usefulCodeFromLibrary.someHelperFunction()
}()

Webpack 2 accessible functions from different js files

Just started using webpack-2 and have a question about global functions. Have these functions in js file named showPictures.js:
function isEmpty(el) {
var result = !$.trim(el.html());
return result;
}
function showPicturesList() {
if (!isEmpty($('#picture-name-list'))) {
var pictureList = document.getElementById("added-pictures");
pictureList.style.visibility = 'visible';
}
}
And I have another file util.js in witch I am calling showPicturesList() function
window.onload = function(){
showPictureList();
}
Simply using js I would import both scripts into my html, but with webpack I can make one file for both of them so webpack.config.js I added both of these files as entry array.
My output file bundle.js looks as it should it has both of those files inside of it. The question is what would be the easiest way with minimal changes on js files to call showPictureList() function from utils.js file?
You can use ES2015/ES6 modules to import your functions which have been exported in another file. In your showPictures.js file you export the functions you want to expose, by adding the export keyword.
export function showPicturesList() {
if (!isEmpty($('#picture-name-list'))) {
var pictureList = document.getElementById("added-pictures");
pictureList.style.visibility = 'visible';
}
}
And then you need to import them in your util.js.
import { showPicturesList } from './showPictures';
For detailed informations on how to use modules you can have a look at Exploring JS: Modules.
With this you also don't need to add both files to entry in your webpack config, because webpack will see the imports and include eveything you're importing.

Categories

Resources