Why does generated ember cli helper export function and helper? - javascript

By default a helper generated by ember-cli looks like this:
import Ember from 'ember';
export function boundLoc(input) {
return input;
}
export default Ember.Handlebars.makeBoundHelper(boundLoc);
I have two questions to better my understanding of this code.
1) Why is there two exports? Does the first export allow the helper to be imported and used by other JavaScript files, whereas the second export is what actually registers it as a Handlebars helper?
2) Secondly, if the code looked like:
import Ember from 'ember';
export default Ember.Handlebars.makeBoundHelper(function boundLoc(input) {
return input;
});
would this export it as a Handlebars template helper but not make the boundLoc() method accessible to other JavaScript files that imported this helper?

1) Yes, there are two exports so that the helper can be used as a function from within other JavaScript after it is imported and as a handlebars helper.
In other JavaScript:
import {
boundLoc
} from 'app/helpers/boundLoc';
boundloc(input);
and in a template:
{{boundloc input}}
2) Yes, the behavior you described is accurate. That would only export a boundHelper and not the function for consumption elsewhere. You can always try a POC.
Note, however, that you may have trouble with generated tests if you try to only export the boundHelper. See this answer for more details.

Related

How to wrap every exported comopnent with HOC?

I need to add to ALL of my React function components the possibility to add [data-test-id] attribute for testing purposes. To achieve that I created withTestId() HOC which adds optional prop testId to wrapped component and when it's defined it adds [data-test-id] to final HTML.
So when I define component like:
<ExampleComponent testId="example" />
it returns:
<div data-test-id="example" />
The only problem I have is to apply it to every component without the necessity to wrap it individually in every component. So instead of writing code like:
function ExampleComponent() { ... }
export default withTestId(ExampleComponent)
I would like to wrap all of my exports in my index.ts file, which right now looks like this:
export { default as ExampleComponent } from "./ExampleComponent";
export { default as ExampleComponent2 } from "./ExampleComponent2";
...
How can I achieve this?
I see two ways of doing this; One dynamic way, making the user-code of your library a bit more convoluted. with you being able to change the implementation easily and another one with a bit more boilerplate code, keeping the user-code as it is.
I haven't tested their behavior regarding tree-shaking when bundling the code.
Using destructing in user-code
This allows to add / remove things from your main component export file without having to worry about additional boilerplate in your library. The higher-order-component can be switched on/off easily. One caveat: The user code needs to use destructuring to retrieve the components.
Your new index.ts file would look like this, while I've called your previous index.ts file components.ts in the same directory:
import * as RegularComponents from "./components";
import withTestId from "./with-test-id";
const WithTestIdComponents = Object
.keys(RegularComponents)
.reduce((testIdComps, key) => {
return {
...testIdComps,
[key]: withTestId(RegularComponents[key])
};
}, {});
export default WithTestIdComponents;
To use it in your application code:
import MyComponents from "./components/tested";
const { Component1, Component2, Component3, Component4 } = MyComponents;
This uses the default export to make it look like you have all components in one place, but since you cannot destructure exports directly, you need this second step to get the correct components out of it.
Add boilerplate to the export file
Since there is an index.ts file with all the components exported in the library, one could import/rename each component and re-export them with withTestId and their name:
import withTestId from "./with-test-id";
import { default as TmpComponent1 } from "./component1";
import { default as TmpComponent2 } from "./component2";
import { default as TmpComponent3 } from "./component3";
import { default as TmpComponent4 } from "./component4";
export const Component1 = withTestId(TmpComponent1);
export const Component2 = withTestId(TmpComponent2);
export const Component3 = withTestId(TmpComponent3);
export const Component4 = withTestId(TmpComponent4);
This way, imports can be used as before:
import {
Component1,
Component2,
Component3,
Component4
} from "./components";
I'd argue that using index files already is some kind of boilerplate and this approach adds to it. Since the user code does not need any changes, I'd favor this approach.
In one of our projects, we have used a custom takeoff script to create this kind of boilerplate for us, whenever we generate a new component.
Examples
Here is a code sandbox to see both approaches.

Import, rename, and export a function in JavaScript?

With JavaScript what's the shortest way to import a named export, rename it, and export it again?
This code works but it feels more verbose than it should be
import { mock as myFunctionMock } from 'context/myFunction';
export const myFunction = myFunctionMock;
You can combine the import and export like so:
export { mock as myFunctionMock } from 'context/myFunction';
See MDN Docs
Note that you won't actually be able to use myFunctionMock within your code file since you haven't imported it. Neither mock nor myFunctionMock will be defined within this module.
This is a useful shorthand when you're building a library that will be used by other modules or by your end-user.
For example, if you had a utils library that you wanted to export, but you wanted to organize your util functions across several smaller files, such as stringUtils, objectUtils, dataUtils, etc, you can export the contents of those modules within your utils module to create a single, monolithic access point:
stringUtils.js
export function toLower(){}
export function toUpper(){}
objectUtils.js
export function propertyMap(){}
utils.js
export {
toLower as stringToLower,
toUpper as stringToUpper,
} from "stringUtils.js";
export {
propertyMap as objectPropertyMap
} from "objectUtils.js";
I wouldn't generally recommend this approach for internal code as it can make your dependency trees a bit wonky in some cases. It can, however, be extremely useful in situations where you want to import from a common interface but the implementation is dependent on the build (prod vs dev, web vs node, etc)
import { mock as myFunction } from 'context/myFunction';
export { myFunction };
in your original exporter, do:
module.exports = { mock: function () {...}}
When importing, do:
const myFunctionMock = require('file path of exporter');
then to reexport in the same file:
module.exports = {renamedMock: myFunctionMock};
Now any changes to mock will propagate to the other modules where it's referenced (side note, this is node.js in a nutshell).

Should I use both `import 'rxjs/Rx'` and `import { Observable } from '#rxjs/Observable'`

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.

Create base class for controller to extend/inherit in Ember application

I'm trying to create a Base Class for my controllers, so I can avoid duplication of code.
The problem here is that it is throwing me errors whenever I try to use it.
"Assertion Failed: You attempted to define a {{link-to "inventory"}} but did not pass the parameters required for generating its dynamic segments. Could not find module controllers/base-inventory imported from frontend/controllers/inventory"
To create my base controller I am using ember cli and this is what I did:
ember g controller base-inventory
Then
// base-inventory.js
const BaseInventory = Ember.Controller.extend({
//my code...
});
export default BaseInventory;
In the controller where I want to use this base class I did the following
import BaseInventory from 'controllers/base-inventory';
// also tried import { BaseInventory } from 'controllers/base-inventory';
// and export default new BaseInventory({});
export default BaseInventory.extend({
//more code here...
});
Any thoughts of what I am doing wrong?
I didn't plan to use mixins, because it doesn't seem the best option here at first. I am not really sure about the sharing content, which mixins provide. I don't think it would be a problem since I'm trying to inherit within controllers, but as I said I'm not sure about how it really works.
If it's not possible to do the way I'm trying to, I'll write a mixin.
Both files are in the same folder structure so import path should be like ./base-inventory
import BaseInventory from './base-inventory';

Ember.JS: Ember-Objects and where they are exported to

I am trying to grasp the underlying system of Ember.JS. Whereto are those Ember-Objects exported and how are they used?
components:
export default Ember.Component.extend({ ... });
controllers:
export default Ember.Controller.extend({ ... });
models:
export default DS.Model.extend({ ... });
routes:
export default Ember.Route.extend({ ... });
... they all follow the same structure: they extend some object and export something.
Somebody knows more? Thanks!
I think you are interpreting the export keyword wrong here.
It doesn't mean files are written somewhere else in a different format, but:
if a module (= file) is imported, then things in that file that are exported are available to the importer.
Think of it as making some parts available to other modules, a public API in shorter terms.
Ember files usually only export one thing as there is a strong naming convention making the Ember engine work that way.
This is why if you declare a /user route, it will try to use your routes/user.js, controllers/user.js, and templates/user.hbs files if they exist, without you having to specify anything.
In a similar way, this is what makes a component usable inside a template.
Hence the one-liner export default Ember.Something.extend({ ... }); you find in these files.
However, you can have modules (= files) with multiple export statements in a single file, this is perfectly valid.
// Example from babel website
// lib/mathplusplus.js
export * from "lib/math";
export var e = 2.71828182846;
export default function(x) {
return Math.exp(x);
}
// app.js
import exp, {pi, e} from "lib/mathplusplus";
console.log("e^π = " + exp(pi));
The Learn ES2015 from Babel website has a few examples, and you can read more about the export statement on MDN.
In Ember applications, you will - from my experience - find files with multiple exports mostly in some directories meant to be used by more than one module in the application, or not bound to the Ember engine auto-import, like some utils.
The following example shows an Ember.Controller importing a variable exported from another module:
// utils/messages.js
export var hello = 'Hello!';
export var bye = 'Good Bye!'
// controllers/hello.js
import { hello } from "utils/messages";
export default Ember.Controller.extend({
firstName: 'David',
helloString: Ember.computed('firstName', function(){
return `${hello} ${this.get('firstName')}`;
})
});

Categories

Resources