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.
Related
I want to make my own javascript library with some utils functions and classes for the client browser. The point its I only want to include the main file.
https://github.com/encarbassot/elioUtils.js
I've tried using the type module
having ./src/array.js, ./src/math.js, ./src/dom.js with some functions with export, thei i have two options
OPTION 1:
/lib/utils.js
import * as array from "./src/array.js"
import * as dom from "./src/dom.js"
import * as math from "./src/math.js"
export {array,dom,math}
but in the script i have to do:
script.js called from html
import {math} from "/lib/utils.js"
const {lerp} = math
the point of modules is to import only the functions you need and here i'am importing all math functions
OPTION 2:
import {zip,create2DArray} from "./src/array.js"
import {isTouchDevice,coptyToClipboard,scrollToCenter} from "./src/dom.js"
import {lerp,inverseLerp,map,clamp} from "./src/math.js"
export {zip,create2DArray,isTouchDevice,CopyToClipboard,lerp,inverseLerp,map,clamp}
but in this example every function i create in some ./src/ file i have to modify the utils.js file
also all libraries i use they dont use module, they are a big class or a big function
i thought about putting all inside a big object like
const utils = {}
utils.lerp = (start,end,amt)=>{
return (1-amt)*start+amt*end
}
// ... and more functions
or using multiple files and then compile them to the big file maybe ???
other option would be to do
document.write('<script src="/lib/src/math.js"></script>');
document.write('<script src="/lib/src/dom.js"></script>');
document.write('<script src="/lib/src/math.js"></script>');
but for what i think its not a very good practice
and last, jQuery you can import the file like a module and like a src file
and i'm trying to avoid things like webpack, i want to keep it vanila
While reading about tree shaking in webpack documentation, I came across this sentence:
In a 100% ESM module world, identifying side effects is straightforward. However, we aren't there just yet.
What do they mean by "100% ESM module" and how it is different from the current import and export that we already use today?
reference: https://webpack.js.org/guides/tree-shaking/#mark-the-file-as-side-effect-free
The documentation you're reading is contrasting two types of scripts:
Scripts which expose everything they do through what they import and export
Scripts which do something in addition to importing and exporting (this could be seen as a "side effect")
Consider a big library, one that installs itself as a namespace on the global object to expose its functionality. Let's say that jQuery did this - that is, that it runs something like
const jQuery = (function() {
// lots and lots of code
})();
export default jQuery;
window.jQuery = jQuery;
This contains a side-effect: the line
window.jQuery = jQuery;
This means that other parts of your application could use window.jQuery without jQuery being specifically imported into that module. For example, you might have
// someModule.js
export const doStuff = () => {
window.jQuery('div').text('Hi!');
};
And this can work without the line
import jQuery from 'jQuery';
inside the module script, because jQuery is on the window. (For this to work, there needs to be at least one module somewhere that does import 'jQuery'; or something like that, so that jQuery's code that assigns itself to the window runs)
Because of the side-effect, Webpack will have a harder time with automatic tree-shaking - you'll have to explicitly note which modules depend on modules with side-effects.
In contrast, a module without dependency side-effects would be the someModule.js example above: all it does it export a function, without adding or changing functionality elsewhere.
So by "100% ESM module", Webpack is probably referring to scripts for which all modules' dependencies are explicit with import statements, instead of having to depend on side-effects (like a non-imported module assigning something to the window).
There are two popular module syntax nodejs use.
Commonjs: https://nodejs.org/dist/latest-v14.x/docs/api/modules.html
// exporting
module.exports.a = 1
// or, exports is an alias to module.exports, for all differences check out docs
exports.a = 1
// you can assign module.exports object as well, this sets what's exported
module.exports = {
b: 2
}
// a is not exported anymore
// importing default import, imports module.exports object
const a = require('./b')
// or via named import
const {c} = require('./b');
ES modules: https://nodejs.org/dist/latest-v14.x/docs/api/esm.html
// names export
export const a = 1;
// default export
export default const b = 2;
// importing via name
import {a} from './c'
// importing default export
import c from './b'
Commonjs and esm are still in use. So we are not in %100 esm world yet.
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;
How to include an entire file into my bundle main.js?
ES6 can import/export functions and classes. But what if i want to include the whole content from another file into my bundle main.js? how to do it?
I came across the query on Stackoverflow: Managing jQuery plugin dependency in webpack.
I'm not sure about this question though. Those options given there seem to target injecting implicit globals, configuring this, disabling AMD, to include large dists. I don't think this is what i want.
Let's say i have two files in src directory
1- rough.js
const rgh = "qwerty"
2- index.js
import './rough.js' //something like this
console.log (rgh)
Now what i expect in bundle.js is
const rgh = "query";
console.log(rgh)
I just want all the content inside one of my file to get all transported to index.js for webpack to bundle them
Those options given there seem to target injecting implicit globals,
configuring this, disabling AMD, to include large dists. I don't think
this is what i want.
To understand this you need to understand what webpack is doing for you. Web pack takes a series of Javascript files (and more importantly their contents) and parses these into one file. That's what it does from a file point of view, but if you ignore the file and think about what it does from a code point of view, it takes each one of the imported objects and makes them available to other objects depending upon the rules you define in your code (using import and export). You can think of this from a closure point of view something like this:
if you have some code like:
import a from 'a.js';
export default b(){
console.log(a.test());
}
This will be turned into something like, in one js file:
var a = (function() {
var testStr = "test";
function test(){
return testStr;
}
return {test:test};
})();
var b = (function(a) {
console.log(a.test());
})(a);
So you can see that the file isn't really important. What's important is the scope. b can use a because it is injected into it's scope (In this instance as a IIFE).
In the above example a and b are in the global scope but testStr isn't.
So when your talking about "importing my file", you need to forget about that and think about what objects in that file you want to import how. Any variables "in that file" declared directly var a = ....; are in the global scope. So it sounds like what you want to do is import the objects in that file into the global scope.
you just need to import that file in main.js
like this way
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.