Is it possible to remove inactive code with Webpack? - javascript

I am importing lodash into my project, but the main script doesn't use more than 5 lodash functions, I don't want to fill my project with unused/inactive code, is there a way to check the whole project structure and delete the inactive code on bundle/on build?
Example:
index.html
<body>
<script src="lodash.js"></script>
<script src="app.js"></script>
</body>
lodash.js
function a() {
console.log('Hi')
}
function b() {
console.log('I am not used anywhere')
}
app.js
...
document.getElementById('main').addEventListener('click', a)
...
Function b() is not used in the project.
Question:
How to get rid of inactive code function b() automatically?

What you want is called Tree Shaking, a pattern that decides which code is dead code and should not be included in the bundle. One of the requirements to use this with Webpack is to use ES Modules. If you're using already webpack to bundle app.js, you should import to import lodash inside your project, instead of adding it as a dependency in your html file.
Keep in mind that this will only work if lodash is using ES Modules, if that's not the case there's always lodash-es

Related

Import 2 Angular projects in another javascript project

I have 2 separated Angular projects.
For each of them, I run the following CLI command:
ng build --prod --output-hashing=none
It creates the following files for each project:
runtime.js
polyfills.js
main.js
Now I want to import the projects into another project, which is a simple javascript project (not Angular project).
I know that the order is important and that runtime.js and polyfills.js appear twice.
So I made sure that these files are the same (because I use the same Angular version in both projects).
The imports in the simple javascript project look something like this:
<script src="runtime.js"></script>
<script src="polyfills.js"></script>
<script src="main1.js"></script>
<script src="main2.js"></script>
Unfortunately, only one of the projects seems to work this way (and there are no exceptions).
If I'll import only main1.js or only main2.js they will work properly.
I guess the problem is the dependency libraries I use in each project, that maybe override each other, but I don't know what I can do about it.
UPDATE:
Not sure if it's relevant, but in each Angular project, I use #angular/elements in order to publish the components I need. something like this:
export class AppModule {
constructor(private injector: Injector) {
const elem = createCustomElement(MyFirstComponent, { injector });
customElements.define('my-first-element', elem);
}
ngDoBootstrap() {}
}
Then in the javascript project, I use it like this:
var elem1 = document.createElement('my-first-element');
container.append(elem1);
var elem2 = document.createElement('my-second-element');
container.append(elem2);
Check the <app-root></app-root> tag in your index.html.
You may need 2 different selector for your AppComponent:
// app.component.ts for the first project
selector: 'app-root-one',
// app.component.ts for the second project
selector: 'app-root-two',

How to package object prototypes in separate file

I have created a number of String.prototype functions which for maintainability I'd like to have in its own file. That is, I'd like to include the file in a javascript project and thus have all the String functions defined.
I could create a module that exports each function, but then I'd have to assign each function as its own String prototype, yes? Something like
var myStringFunctions = require("myStringFunctions");
String.prototype.func1 = myStringFunctions.func1;
Is there a way to include such a file so that the prototypes are defined as part of the inclusion?
Try it, you will see your code and using require("./myStringFunctions"); works just fine.
./myStringFunctions.js
String.prototype.func1 = function() {
return this.toUpperCase(this);
};
./index.js
require("./myStringFunctions");
console.log("foo".func1()); // FOO
If your JS is going to run in the browser, you can use JS modules with the import and export syntax if you use a module bundling build tool like Webpack: https://webpack.js.org/ .
If your JS is running in a Node.js environment, modules are supported: https://www.w3schools.com/nodejs/nodejs_modules.asp

Accessing webpack/bundled React Class from .html file

Is it not possible to access already 'built' components within the html file that the build is linked to?
I am trying the following -
In bundle.js
var React = require('react');
var ReactDOM = require('react-dom');
var Titles = React.createClass({
render() {
return (
<div>
<h1>{this.props.headerProp}</h1>
<h2>{this.props.contentProp}</h2>
</div>
);
}
});
In my html page -
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.3/JSXTransformer.js"></script>
<div id="con"></div>
<script type="text/javascript" src="/public/bundle.js'"></script>
<script type="text/jsx">
ReactDOM.render(<Titles headerProp = "Header from props..." contentProp = "Content
from props..."/>, document.getElementById('con'));
</script>
But console outputs React is not defined.
I have even tried to set react globally within the bundle -
window.React = React;
And calling it with window. prefixed but yields the same result.
Because you're mentiong a bundle.js file with a snippet containing commonjs style imports, I'm assuming you're using Webpack.
I have some considerations about your code.
bundle.js file will not expose any module as global. That includes React and any other module you might require inside the bundle. There isn't goint to be window.ModuleName. However, these module are accessible in the Browser via require.js because Webpack will export modules as UMD, that is, they will be accessible through either commonjs or AMD (Require.js).
I'm pretty sure that, if in the entry point of your webpack configuration file, you do something like var React = require("react"); window.React = React, that's actually going to work.
There's a Webpack module meant to expose modules globally (like in window.x) in a more ellegant way than (2) called expose-loader. You should take a look at it.
You should really try to avoid doing what you're trying to do. In your entry.js file (the entry point of your webpack configuration) should be responsible for doing something like ReactDOM.render(..., document.getElementById("#app")). So that, just by including your bundle, the app will render automatically. This is what everybody does.
JSXTransformer.js as well as the <script type="text/jsx"> have been deprecated a long time ago. Now you're supposed to use Babel to compile React.

How to include anonymous functions into RequireJS dependencies?

I am starting to use RequireJS now and I was already able to add my project dependencies but I still cannot add a jQuery anonymous function yet.
For example, with my normal_file.js I do something like:
normal_file.js:
define(['dependency1'], function(Dependency) {
var Test1 = ...;
return Test1;
});
Bu from a file that has no module, like the example below, I don't know how to encapsulate it:
lib_file.js:
(function ($) {
// Do stuff...
})(window.jQuery);
the lib_file was not made by me and I'm not sure on how it really works, but I would gess it is an anonymous auto-executed function, is that so?.
Anyway, my goal is to use both files in my main code, like below:
main.js:
requirejs.config({
baseUrl:'/static/editorial/js/',
paths: {
jquery: 'third_party/jquery-1.10.2',
react: 'third_party/react-with-addons'
}
});
var dependencies = [
'third_party/react-with-addons',
'third_party/jquery-1.10.2',
'build/utils/normal_file,
'third_party/lib_file
];
require(dependencies, function(React, $, Test1, ??) {
// do my stuff
});
How should I encapsulate that anonymous function in order to add it as a dependency to my main file?
From the RequireJS docs:
Ideally the scripts you load will be modules that are defined by
calling define(). However, you may need to use some traditional/legacy
"browser globals" scripts that do not express their dependencies via
define(). For those, you can use the shim config. To properly express
their dependencies.
Read this: http://requirejs.org/docs/api.html#config-shim
It has a really good explanation of what you have to do, and gives a nice example.
Basically, you just need to set up a shim config for lib_file.js so Require knows to load the right dependencies before giving you access to that script.

Using JQuery etc. in TypeScript with RequireJS [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
How to require jquery via AMD in TypeScript
I created a project in TypeScript. I use RequireJS. Everything was working fine, until I need JQuery...
This is my files structure:
As you can see, I have jquery-1.8.d.ts file in the modules folder. The .js file for jQuery is inside the lib folder. When I import a module using the config file for RequireJS:
/// <reference path="../modules/require.d.ts" />
/// <reference path="AppMain.ts" />
require.config({
baseUrl: '../',
paths: {
jquery: 'lib/jquery-1.8.3'
},
shim: {
jquery: {
exports: '$'
}
},
name: "app/AppMain",
out: "../!built/Test.js",
optimize: "none"
});
require(['jquery', 'app/AppMain',
],
($, main) => {
var appMain = new main.AppMain();
appMain.run();
});
... then it's imported in JavaScript. What to do if I want it inside TypeScript? I need to use JQuery, JQueryStatic and JQueryPromise, declared inside .d.ts file.
When I try simply import a new module, I get an error:
import JQueryExternal = module("../../../modules/jquery-1.8.d"); // error: The name does not exist in the currect scope. A module cannot be aliased to a non-module type
interface Test {
MyMethod(): JQueryPromise; // here's a sample usage
}
In the beginning I thought that the path is wrong, but I tried to move it inside classes folder and next I imported it in such a way as the rest of classes. Same error:/
How to use jQuery in TypeScript in a way I want to? Is it possible?
This is completely confused:
import JQueryExternal = module("../../../modules/jquery-1.8.d");
You don't import the definition file as a module in order to use it in TypeScript. Whether you are using AMD/RequireJS or Node.js style modules to import the eventual code, you always reference d.ts definition files in the same way, at the top of your document:
/// <reference path="YOUR-RELATIVE-PATH-HERE/jquery.d.ts" />
This doesn't make the library available in JavaScript, but it will make the definitions available as you write your TypeScript.
I'm working on a large application similar in scope to yours which makes heavy use of RequireJS and JQuery. I can't see any benefit to loading JQuery as a module. I just import the reference (as described above), and make sure my page loads JQuery (and any other libraries) first:
<script type="text/javascript" src="//ajax.aspnetcdn.com/ajax/jQuery/jquery-1.8.2.min.js"></script>
<script type="text/javascript" src="//ajax.aspnetcdn.com/ajax/jquery.ui/1.9.0/jquery-ui.min.js"></script>
... etc ...
<script type="text/javascript" src="/content/client/libs/require.js" data-main="/content/client/pe.framework"></script>
I had some trouble with these two playing nicely together, so when I use requireJS with JQuery, I use a bundled version that loads them both. I don't know typescript, though, so I'm not sure how helpful this will be.
Link to the bundle: https://github.com/jrburke/require-jquery

Categories