Webpack 5 runtime and dependOn property - webpack-5

I'm mostly confused as to what the runtime property is actually doing for a webpack entry point. Referenced here:
And even more confused when the documentation makes this statement:
What exactly is the runtime chunk for an entry point and how does it relate to that limitation.
Ty!
Link to full page here

By default, each entry point will have an embedded runtime. The runtime can be think of as an mechanism to record the module import/export record, so you won't have duplications of module initialization. By specifying runtime you're telling webpack to create-or-reuse a runtime. On the other hand, with dependOn you can reuse a runtime by specifying an existing entry name. Since these two ideas overlap, so you probably won't want to do it at the same time.

You have to understand first what runtime and dependOn actually are.
runtime
Take this as an example:
src/myModule.js
export const textToPrint = 'Hello world!';
src/index.js
import { textToPrint } from "./myModule";
console.log(textToPrint);
webpack.config.js
module.exports = {
entry: {
myEntry: {
// runtime: 'myRuntime',
import: './src/index.js',
}
}
};
dist/index.html
<!DOCTYPE html>
<html>
<head>
<!-- Don't forget to uncommet this line when using the
`runtime` property in the webpack configuration -->
<!-- <script src="./myRuntime.js"></script> -->
<script src="./myEntry.js"></script>
</head>
<body></body>
</html>
Running npx webpack --mode='development' will generate a dist/myEntry.js file wich will, among other things, create and use a __webpack_require__() function:
// ...
/******/ function __webpack_require__(moduleId) {
/******/ // Check if module is in cache
/******/ var cachedModule = __webpack_module_cache__[moduleId];
/******/ if (cachedModule !== undefined) {
/******/ return cachedModule.exports;
/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = __webpack_module_cache__[moduleId] = {
/******/ // no module.id needed
/******/ // no module.loaded needed
/******/ exports: {}
/******/ };
/******/
/******/ // Execute the module function
/******/ __webpack_modules__[moduleId](module, module.exports, __webpack_require__);
/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }
// ...
Now, if you uncomment the runtime: 'myRuntime' line in webpack.config.js and rerun the webpack command, you will see now that the __webpack_require__ function is not generated anywhere in dist/myEntry.js. You might see __webpack_require__ here and there in that file, but they are only references to the parameters of the function, not the function itself.
In dist/myRuntime.js, however...
As you can see, it's there. With this we can conclude that the runtime is the part of the bundle with the functions that are used in other parts to load the modules. Whether those functions are or not in the same file depends on whether you use this option or not. The advantage is that you can have smaller chunks with this code stripped away in a separate file instead of having this code duplicated in all entry points. The disadvantage however is that because this runtime file is meant to be used in other files, Webpack cannot predict what functionalities are not used, so Webpack keeps them (This is just a theory, I am not 100% sure this is the actual reason why the runtime has more things when in a separate file).
Don't forget to discomment the <script src="./myRuntime.js"></script> line in dist/index.html. Because this script contains the functionality to load modules, it obviously has to be loaded before other scripts.
dependOn
Let's suppose we have now these files in our project:
src/index.js
globalThis.messageToPrint = 'Hello world!';
src/foo.js
console.log(globalThis.messageToPrint);
In this case, because foo.js is using a global variable whose value is set by index.js, it obviously depends on index.js so we tell Webpack about this to have the bundles configured properly:
webpack.config.js
module.exports = {
entry: {
myEntry: {
import: './src/index.js',
},
mySecondEntry: {
import: './src/foo.js',
dependOn: 'myEntry'
}
}
};
We also have to remember to load the scripts in order in our html file, like so:
_index.html
<!DOCTYPE html>
<html>
<head>
<script src="./myEntry.js"></script>
<script src="./mySecondEntry.js"></script>
</head>
<body></body>
</html>
Remember what I told you about runtimes? Because we didn't use the runtime property this time, in theory both myEntry.js and mySecondEntry.js should have the runtime code in them. But because the runtime is loaded already in myEntry, it doesn't make sense to also load it in mySecondEntry, so it is automatically stripped from that file.
Why can't we specify both runtime and dependOn in the same entry in the webpack configuration file then?
Because both runtime and dependOn would strip the runtime from the entry file. One because the runtime would be in a separate file so that other entires can reuse it, and the other because the runtime is already loaded by the dependency. Having both wouldn't make sense because the dependency would in some way or another have this runtime loaded anyways. In the same file or in the runtime file, the dependency would load it. If you want both to specify a dependency and have the runtime in a separate file, then using this example you would have to specify the runtime property in myEntry and dependOn in mySecondEntry.

Related

Reactjs SPA stopped working after splitting code, ( static bundle is not loading from AWS S3)

My website has been working well before my recent change. The website front-end is on reactjs, and bundle is on aws s3. Everything is good till this point.
Now because of huge size of static bundle and also to optimize my code, I started splitting code via webpack split code, lazy loading of react component and dynamic import. I am using webpack-bundle-tracker to create bundle because my back-end is on django. This new setup is working well on my local environment.
DEV environment:
<script type="text/javascript" src="/static/frontend/main.35952edee77e6e3f52e5.bundle.js" ></script>
And this loads very well formatted code to load on my local environment:
DEV environment:
/******/ (function(modules) { // webpackBootstrap
/******/ // install a JSONP callback for chunk loading
/******/ function webpackJsonpCallback(data) {
/******/ var chunkIds = data[0];
/******/ var moreModules = data[1];
/******/
/******/
/******/ // add "moreModules" to the modules object,
/******/ // then flag all "chunkIds" as loaded and fire callback
/******/ var moduleId, chunkId, i = 0, resolves = [];
/******/ for(;i < chunkIds.length; i++) {
/******/ chunkId = chunkIds[i];
/******/ if(Object.prototype.hasOwnProperty.call(installedChunks, chunkId) && installedChunks[chunkId]) {
/******/ resolves.push(installedChunks[chunkId][0]);
/******/ }
/******/ installedChunks[chunkId] = 0;
/******/ }
/******/ for(moduleId in moreModules) {
/******/ if(Object.prototype.hasOwnProperty.call(moreModules, moduleId)) {
/******/ modules[moduleId] = moreModules[moduleId];
/******/ }
/******/ }
/******/ if(parentJsonpFunction) parentJsonpFunction(data);
/******/
/******/ while(resolves.length) {
/******/ resolves.shift()();
/******/ }
/******/
/******/ };
But when I deploy code on heroku, and push static bundles on aws s3, it stops working. It doesn't throw any error, so I am not able to understand the reason of this issue.
Prod env
<script type="text/javascript" src="https://ecmsdjango-main.s3.amazonaws.com/staticfiles/main.54a39fc868c800757af7.bundle.js" ></script>
Further if I click on the above aws link I can see the static content, but this is not in a good format as I could see on my local environment.
Prod env
(window.webpackJsonp=window.webpackJsonp||[]).push([[0],{1003:function(e,t,n){},1004:function(e,t,n){"use strict";n.r(t);var r=n(0),a=n.n(r),o=n(81),s=n(12),i=n(38),c=n(1),l=n.n(c),u=n(14);function p(e){return(p="function"==typeof Symbol&&"symbol"==typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"==typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function m(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}function d(e,t){return!t||"object"!==p(t)&&"function"!=typeof t?function(e){if(void 0!==e)return e;throw new ReferenceError("this hasn't been initialised - super() hasn't been called")}(e):t}function h(e){return(h=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)})(e)}function f(e,t){return(f=Object.setPrototypeOf||function(e,t){return e.__proto__=t,e})(e,t)}var g=function(){function i(){var e,t,a;!function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}(this,i);for(var n=arguments.length,r=new Array(n),o=0;o<n;o++)r[o]=arguments[o];return d(a,(t=a=d(this,(e=h(i)).call.apply(e,[this].concat(r))),a.state={username:"",password:""},a.onSubmit=function(e){e.preventDefault(),a.props.login(a.state.username,a.state.password)},a.onChange=function(e){return a.setState((t={},n=e.target.name,r=e.target.value,n in t?Object.defineProperty(t,n,{value:r,enumerable:!0,configurable:!0,writable:!0}):t[n]=r,t));var t,n,r},t))}var e,t,n;return
So basically the website doesn't load any thing (its blank) but underlying bundles have static content in it. So it appears to me that something is linked with the loader or could
be the way aws s3 loads the chunks, but I haven't got root cause yet, please help me to fix this.
For example: website is showing old version before code split, if I deploy the latest code, it will be blank.
P.S. For now I am tagging it with react js, django as well because main reason of code split was optimization of my react front-end, and bridging it with django but both of these tags can be removed.
The issue is happening because of webpack split chunks optimization config, I have removed that config from prod and it was all looking okay. I have not this extra optimization in webpack dev config.
I am marking it as an answer, because now I know the root cause and its not an aws s3 or webpack issue, and overall its no longer a problem now.

Is it possible to read property from portal-ext.properties using JavaScript or api/jsonws in Liferay 7.1?

I am defining the AMD module under OSGi module. I have to read host property in AMD loader definition. how can I read the property from portal-ext.properties file?
below is sample code how I am defining the AMD module and property in portal-ext.properties file.
portal-ext.properties
# host detail
host={{host_url}}
define AMD module
Liferay.Loader.define('genelec-shopping-cart', [], function(){
const host = ""; //here i have to read the property
return{
getHost:function(){
return host;
},
};
});
You can do this with ftl or jsp, building your JS with the value embedded.
Instead of creating the whole code from a JSP you can also just build a small portion of it, adding the value to a JS variable, making it available for scripts that will load later.
Let's say you have an OSGi module which JS code, you can create a .js.jsp that will build the JS before sending it.
Using JSP to create a small portion of JS:
<%# page contentType='application/javascript' %>
//here i have to read the property -> do it in java
Liferay.Loader.define('genelec-shopping-cart', [], function(){
const host = "${read_in_java}";
return{
getHost:function(){
return host;
},
};
});
You can include it from other JSP files as:
<c:url var='url' value='/variables.js.jsp'>
<c:param name='namespace' value='${namespace}'/>
</c:url>
<script src='${url}'></script>
But as you mentioned the host, you are probably looking for something much simpler than that (especially because this is kind of a hack), using Liferay's JS api:
Liferay.ThemeDisplay.getPortalURL() and friends, docs here:
https://dev.liferay.com/de/develop/tutorials/-/knowledge_base/7-1/liferay-javascript-apis

Ember-cli how to change input path of files

I am new to ember. But for a particular task i need to change input path of templates to compile. i.e default is app/templates. but i want to change this path.
I have read the ember-cli-build.js file but i can edit only output path. how can i edit the input path.
My ember-cli-build.js
var EmberApp = require('ember-cli/lib/broccoli/ember-app');
module.exports = function(defaults) {
var app = new EmberApp(defaults, {
// Add options here
outputPaths: {
app: {
html: 'ember_build_index.html'
}
}
});
// Use `app.import` to add additional libraries to the generated
// output files.
//
// If you need to use different assets in different
// environments, specify an object as the first parameter. That
// object's keys should be the environment name and the values
// should be the asset to use in that environment.
//
// If the library that you are including contains AMD or ES6
// modules that you would like to import into your application
// please specify an object with the list of modules as keys
// along with the exports of each module as its value.
app.import('bower_components/bootstrap/dist/js/bootstrap.min.js');
app.import('bower_components/bootstrap/dist/css/bootstrap.min.css');
app.import('bower_components/bootstrap/dist/css/bootstrap.css.map');
return app.toTree();
};
You have to change templates directory path for the ember app being built.
To check your current templates directory path, check app.trees.templates._directoryPath in your ember-cli-build.js by log it to console using console.log(app.trees.templates._directoryPath) .
Now, if you want your ember build to have templates from 'app/templates/mobile' (in your case), just change:
app.trees.templates._directoryPath = 'app/templates/mobile' in ember-cli-build.js before it returns app.toTree();
The node_module which constructs tree for templates is at 'node_modules/ember-cli/lib/broccoli/ember-app.js' at line no. 724 where it accesses 'this.trees.templates' in which this is the instance of your app.

Peeking behind ember-cli (EmberApp): vendor.js and app.js

With the excellent broccoli-stew I can take a look at the exported application tree:
/* global require, module */
var EmberApp = require('ember-cli/lib/broccoli/ember-app');
var log = require('broccoli-stew').log;
var debug = require('broccoli-stew').debug;
var app = new EmberApp();
// Use `app.import` to add additional libraries to the generated
// output files.
//
// If you need to use different assets in different
// environments, specify an object as the first parameter. That
// object's keys should be the environment name and the values
// should be the asset to use in that environment.
//
// If the library that you are including contains AMD or ES6
// modules that you would like to import into your application
// please specify an object with the list of modules as keys
// along with the exports of each module as its value.
app.import('bower_components/ember-i18n/lib/i18n.js');
app.import('bower_components/raphael/raphael.js');
var finalTree = log(app.toTree());
module.exports = finalTree;
With this I get a very clean tree-like output of my application:
[ 'assets/app.js',
'assets/app.map',
'assets/app.scss',
...
'assets/vendor.css',
'assets/vendor.js',
'assets/vendor.map',
'crossdomain.xml',
'index.html',
'robots.txt',
'testem.js',
'tests/index.html' ]
I see that in that tree we have, among other files, a vendor.js and an app.js modules (as expected), but I do not know what packages are put into each of them.
I have the feelling I am missing one in my frontend (in this case, raphael.js), so I would like to verify that ember-cli (via EmberApp) has indeed done what I asked for (namely, include the raphael.js, probably in vendor.js)
Taking a direct look at app.js or vendor.js is not feasible (too big / don't know what to look for). I want a simple tree-like display of the files that have been included by EmberApp into vendor.js / app.js, in the same (similar) format that broccoli-stew is providing.
Is this possible? How?
To quote http://www.ember-cli.com/asset-compilation/#configuring-output-paths:
Assets Output File
JavaScript files you import with app.import() /assets/vendor.js
So although that is not a nice tree view, you should be fine :-)

Using backbone.js' text.js plugin cannot access template

I get the error GET localhost:8080/scripts/templates/home/homeTemplate.html 404 (Not Found)
Not sure why this is happening. Based on this tutorial I feel like files are in the right place. http://backbonetutorials.com/organizing-backbone-using-modules/
The github repository is here https://github.com/natecraft1/backbone-widget
I reference the template like this
'text!templates/home/homeTemplate.html'
from app/templates/home...
Modify the scripts/main.js as follows.
require.config({
paths: {
jquery: 'libs/jquery',
underscore: 'libs/underscore',
backbone: 'libs/backbone',
templates: '../templates' // added
}
});
require(['app'], function(App) {
App.initialize();
});
By setting the templates as above,
if the module ID starts with "templates",
requirejs load the module from the templates directory
Without the above templates setting, requirejs load any module IDs from scripts directory, which contains main.js source code. Thus the text!templates/home/homeTemplate.html is interpreted as wrong URL scripts/templates/home/home/homeTemplate.html.
If you do not want to modify the main.js script,
you can specify the correct location of homeTemplate.html by
replacing the 'text!templates/...' with
'text!../../../templates/home/homeTemplate.html' or
'text!/../templates/home/homeTemplate.html'