We use lodash in an angular app written with typescript. Currently we import lodash as follows:
import * as _ from 'lodash';
//.. code which uses _.pluck()
However, for the sake of tree shaking, we want to change to the following:
import {pluck, delay} from 'lodash';
//.. code which uses _.pluck() needs changed to pluck()
The problem is we need to do a lot of tedious code changes because using the second import method loses the namespace of _ and there could be name conflicts. Is there a way of specifying the things we want to import but maintain the namespace? I was thinking something as follows, but it doesn't work:
import {pluck, delay} as _ from 'lodash';
//.. code which uses _.pluck() needs changed to pluck()
Not directly in import but you can create the _ object manually.
import { pluck, delay } from 'lodash';
const _ = { pluck, delay };
Related
I was browsing through this repo on Github and was trying to comprehend the working of the code
Here, the author (or programmer) have mentioned import * at multiple places so I am trying to comprehend and understand how import * work?
First in Game.js file of his repo he have mentioned/written like this
import * as actions from '../actions';
In VS Code, when if I click on '../actions using command It is redirecting me to this file -> index.js
then in Index.js they have something like this
import * as ActionTypes from './action-types';
when I click on ./action-types it redirects me to here action-types.js
I went through firefox docs but I wasn't able to clearly make sense for the first example like for one, the action folder contains multiple files and how does import * as actions from '../actions'; mean index.js file
While i get he have called/referenced the functions using actions.functionName() or ActionType.TypeName
My Prime question remains
how does import * as actions from '../actions'; mean index.js file ?
The import * as name syntax imports all exported content of a javascript file.
For example, if you want to import an entire module's contents, then access the doAllTheAmazingThings() function
import * as myModule from '/modules/my-module.js';
myModule.doAllTheAmazingThings();
From the docs
Import in js is new syntax of ES6 to import a module it has the same work of require but its easier to filter what do you want in a module
In your example you import * as actions from '../actions'; you import all function from ../actions file
its same to do const actions = require('../actions')
but its easier to manage what you want
this syntax is not work on all browser so be sure to use transpiler with babel or other
you can see this syntax in python too
When you reference a directory in an import statement, it looks and loads the index.js file in that directory. What I usually do there is export classes and functions under that directory in a grouped object, so they can be easily accessed:
For instance in index.js I export sth like:
{
Class1,
method1
}
where each is imported as such:
import Class1 from './Class1';
So they just group the classes/methods/... that are in files in the directory.
Then you can easily access it as such:
import { Class1, method1 } from './mymodule';
vs
import Class1 from './mymodule/Class1';
import { Injectable } from '#angular/core';
import { Headers, Http, Response } from '#angular/http';
import { Observable } from '#rxjs/Observable';
import 'rxjs/Rx';
import 'rxjs/add/observable/throw';
#Component({});
export shellModule{}
This is a piece of code form my Angular app that I copied from somewhere (I have removed the definitions in the exported module. I am using it to make a service to call APIs.
In the imports in this particular file, why is it that Observable is imported separately even though the entire rxjshas been imported. If a particular module is being imported in its entirety, why is a particular object from it imported separately? I tried asking this question at the forum from where I took it, but there was no answer. I want to understand if this somehow helps with optimization of code.
In general:
In Typescript, the way modules are handled would require you to either load in the entire library with the import * as rx from 'rxjs/Rx', or a specific exported module within the library to use it, so the the compiler loads in the types.
Reducing your imports to only the specific modules you need sets up your app to use tree shaking from Angular's AOT compilation. This is not done by the typescript compiler, but by a tool called rollup. So, it can help with optimizing code later, but it doesn't automatically do so.
As far as compilation overhead, bringing in the whole library might slow down the compiler a bit... but this isn't a very strong point except for massively complex libraries.
I, personally, prefer importing in specific modules because it makes the calling code a little cleaner since I don't need to use that global name to get to the specific name. rx.Observable vs Observable. A good example of this is the lodash library (rxjs is a bit more complex...)
Honestly, importing entire libraries like the line you have there: import 'rxjs/Rx' doesn't make sense to me. You should only import specific exported modules. Try removing it, seeing what errors you get, and then using the * as rx syntax instead.
As far as rxjs goes - it is a little wonky when you want to import specific operators like this question does - so the way to get specific operators is with: import 'rxjs/add/observable/from' - but that also requires a tinkering with your webpack set up as outlined in the referenced question's answer.
Let's see what the rxjs/Rx module exports:
export { Subject, AnonymousSubject } from './Subject';
export { Observable } from './Observable';
export { Operator } from './Operator';
export { Observer } from './Observer';
export { Subscription } from './Subscription';
export { Subscriber } from './Subscriber';
export { AsyncSubject } from './AsyncSubject';
export { ReplaySubject } from './ReplaySubject';
export { BehaviorSubject } from './BehaviorSubject';
...
import './add/observable/bindCallback';
import './add/observable/bindNodeCallback';
import './add/observable/combineLatest';
...
So it exports RxJs classes and also imports operators from the add folder. So as you can see it loads everything in the library. It doesn't export any global object though. So you need to use named export like this:
import * as Rx from 'rxjs/Rx'
to be able to use an exported class:
Rx.Observable.of(12, 3);
This emulates what you would have if you loaded the library using the bundle - a global Rx object:
<script src="rxjs/bundles/Rx.js">
If you want to use Observable without Rx global object, you need to import it separately:
import { Observable } from '#rxjs/Observable';
Observable.of(1);
Importing both
import { Observable } from '#rxjs/Observable';
import 'rxjs/Rx';
is not a good practice, but may be used if you don't want to import every operator separately.
Also see How to correctly import operators from the rxjs package.
Im trying to use object destructing imports in my code.
I would like to import only map and extend in my component.
Would I do
import { map, extend } from lodash;
How can I use it in my code?
Javascript also has a map, so if I do
let arr = [1,3,4];
arr.map((item) => console.log(item))
How can I refer to lodash map, not the actual map method?
PS: Im trying to understand object destructing methods. I know I can use ES6 map, this is just an example.
This is a default import.
import _ from 'lodash';
_.map(...);
This is a named import.
import { map } from 'lodash';
map(...);
Using map() as a method of the default import and as a standalone function are essentially the same (with the only meaningful difference being the value of this). Which syntax works is up to the library you are importing. You can only use a default import if the library defines a default export and same for named imports / exports. Both can also be used at the same time, though this is a bit unusual.
The default import can be named whatever your heart desires. If you want to confuse people and pretend that Lodash is jQuery, you can do so.
`import $ from 'lodash';`
On the other hand, named imports have specific names that they are bound to. So unlike the default import, trying to use the named import syntax on $ vs _ refers to an entirely different object and will throw if not defined as an export within the library.
// These are very different.
import { $ } from 'lodash';
import { _ } from 'lodash';
If it becomes necessary, you can "rename" a named import.
import { map as crazyFunc } from 'lodash';
In the above case, crazyFunc can be named whatever your heart desires, but map must remain as-is, otherwise it will refer to an entirely different object and will throw if not defined as an export within the library.
It may help to understand that these are equivalent.
import { default as _ } from 'lodash';
import _ from 'lib';
The latter is simply sugar for the former. And the default export syntax is sugar for creating a named export with the name default.
For more info (including features not covered here), see ES6 modules syntax.
Full example:
import { map } from 'lodash';
const squares = map([4, 8], (n) => {
return n * n;
});
console.log(squares); // => [16, 64]
I read somewhere (forgot the source, unfortunately), that it's more efficient somehow to do this:
import _find from 'lodash/find';
as opposed to:
import _ from 'lodash'; // just to use _.find
I understand how it could be more efficient to import a single function, but where is the efficiency/performance gain exactly? Is it webpack-related? If I'm not using webpack as my build engine, does it matter?
When you import a big library, you import the whole thing (at least with most bundlers), since there is no clear way to distinguish what is necessary from the object you imported.
I'm not too familiar with lodash but it's entry point should look something like this:
module.exports = {
find: require('./find.js')
filter: require('./filter.js')
// rest of the exposed functions
}
With the second import style you got this whole object, but you only need 1 function from all of this.
So if you do this:
import _ from 'lodash'
You will end up with the whole lodash library packed into your bundle, while if you do this:
import find from 'lodash/find'
You will only have find and it's dependencies, resulting in a considerably smaller bundle size.
Can I use lodash _ in all of my vue component?
for example:
I have components organized like below:
App.vue > Parent.vue > Child.vue
I would like all of my component to access _ lodash without defined in every component vm data
===
I am also trying using Mixins. it works. but the result not expected like this _().isEmpty() instead of _.isEmpty()
Some of the current answers may work in your scenario, but they have downsides:
Adding to the window object means your Vue project can't be server rendered, because servers don't have access to the window object.
Importing in every file works fine, but it can be a pain if you have to remember to do it in every file.
An alternative approach is to add your library to the Vue prototype. All components inherit from this so they will now all be able to access your library from the this keyword.
import _ from 'lodash';
Object.defineProperty(Vue.prototype, '$_', { value: _ });
Now lodash is available as an instance method for all components. In a .vue file you can do this without importing anything:
export default {
created() {
console.log(this.$_.isEmpty(null));
}
}
The advantage of using Object.defineProperty rather than a normal property assignment is that you can define a descriptor which allows you to make the property read-only, which it will be by default. This stops consuming components from overwriting it.
This is more thoroughly explained in this blog post (which I wrote).
Note: The downside to this approach is that you get the entire Lodash library, even if you only need one or two functions. If that's a problem, best to use import { reduce, whatever } from "lodash"; at the top of the file requiring it.
You could import the lodash into each component:
<script>
import _ from 'lodash'
export default {
methods: {
test (value) {
return _.isEmpty(value)
}
}
}
</script>
For inline templates separated from the js module code it should work with:
Vue.component('some-tag', {
computed: {
_() {
return _;
}
}
});
And then you can use it in template in "native" way - _.isEmpty(value).
import _ from 'lodash'
Vue.prototype._ = _
Insert these lines in your main.js file and it will work all over your app.
You could import lodash globally like this
window._ = require('lodash');
Once that has been imported, you will have access to _ from anywhere.
A simple approach that worked for me:
Vue.set(Vue.prototype, '_', _);
This should allow you to use _ in all component templates and vue instances.
You can use plugin/mixin like this.
import _ from 'lodash';
exports default {
install : function(Vue, options){
Vue.mixin({
computed : {
"_" : function(){
return _;
}
}
});
}
}
Bit late to the party but through my research of finding a way to import lodash and other libraries into all my .vue files, I encountered the webpack ProvidePlugin, which achieves everything the OP requested with almost no fuss. To implement this solution, following this fantastic tutorial.
I would note that in the tutorial, he left import "jquery" in his app.js file, which is not required. The plugin with import it automatically.
Check out vue-lodash!!
It's a new wrapper for using lodash in vue.
You can call it using
Vue._.random(20) // for getting random number between 20
this._.random(20) //or other method you want to use
in any of the component file :)
The proper way is to use provide / inject as such:
import _ from 'lodash';
const app = createApp({
provide: {
$_: _,
}
});
Then in аnоthег component:
<script>
export default {
name: 'аnоthег-component',
inject: [
'$_'
]
}
</script>
You can also create a base component and make all of your components extend it.
// base-component
import _ from 'lodash';
export default Vue.extend({
computed: {
_() {
return _;
},
},
});
// my-component
import BaseComponent from 'path/to/base-vue';
export default BaseComponent.extend({
template: '<p>Lodash is available: {{!!_}}</p>'
methods: {
doSomehting() {
// `this._` should be available
},
},
});
The pro of this approach is it's not intrusive, so no possible conflict with Vue in the future. Also, you can add even more things to the BaseComponent, like other libraries and external services, and they will be available to all other components.
The con is it's more verbose and you have to remember to inherit from the base component.
For vue users
Go to main.js
import _ from 'lodash'
Vue.set(Vue.prototype, '$_', _)
For nuxt.js users
create main.js inside plugin folder
plugin/main.js
import _ from 'lodash'
Vue.set(Vue.prototype, '$_', _)
Then add into
nuxt.config.js
plugins: ['~plugins/main.js'],
usage are same in both vue and nuxt js
then use in component
this.$_.map(arra,(x)=>{})