PeterStaev / NativeScript-Drop-Down

A NativeScript DropDown widget.
Apache License 2.0
105 stars 65 forks source link

Nativescript drop down doesn't support latest {N} namespacing #254

Closed schnapzz closed 3 years ago

schnapzz commented 3 years ago

Project info node: v14 N-cli: 7.0.11 N-core: 7.0.13 ios-runtime: 7.0.6 android-runtime: 7.0.1 Drop-down: 5.0.6 (latest)

Description of problem 1: Build fails during ns build ios or ns build android with the following error:

ERROR in ../node_modules/nativescript-drop-down/drop-down.js
Module not found: Error: Can't resolve 'ui/editable-text-base/editable-text-base' in '<project root>/node_modules/nativescript-drop-down'
 @ ../node_modules/nativescript-drop-down/drop-down.js 6:27-78
 @ ./views/user/user-login-page.js
 @ . sync (?<!\bApp_Resources\b.*)(?<!\.\/\btests\b\/.*?)\.(xml|css|js|(?<!\.d\.)ts|(?<!\b_[\w-]*\.)scss)$
 @ ./app.js
Executing webpack failed with exit code 2.

This can be fixed easily by updating the requires in drop-down.ios.js and drop-down.android.js and i've done so for quite some time .If time permits i'll send a PR with this update.

Description of problem 2: With the updated namespacing, the app is buildable. The next issue comes when using the drop-down menu, which causes the following error:

***** Fatal JavaScript exception - application has been terminated. *****
NativeScript encountered a fatal error: Uncaught TypeError: Cannot read property 'getDefault' of undefined
at
(file: node_modules/nativescript-drop-down/drop-down.ios.js:137:0)
at (file: node_modules/nativescript-drop-down/drop-down.ios.js:216:1)
at ../node_modules/nativescript-drop-down/drop-down.js(file:///app/vendor.js:116942:30)
at __webpack_require__(file: app/webpack/bootstrap:816:0)
at fn(file: app/webpack/bootstrap:120:0)
at (file: app/views/user/user-login-page.js:2:23)
at ./views/user/user-login-page.js(file:///app/bundle.js:8891:30)
at __webpack_require__(file: app/webpack/bootstrap:816:0)
at fn(file: app/webpack/bootstrap:120:0)
at webpackContext(file: app/\b_[\w-]*\.)scss)$:84:0)
at loader(file: node_modules/@nativescript/core/globals/index.js:158:0)
at loadModule(file: node_modules/@nativescript/core/globals/index.js:202:0)
at createViewFromEntry(file: node_modules/@nativescript/core/ui/builder/index.js:25:0)
at getModalOptions(file: node_modules/@nativescript/core/ui/core/view/view-common.js:258:86)
at showModal(file: node_modules/@nativescript/core/ui/core/view/view-common.js:265:31)
at openUserCreationView(file: app/views/user/user-page.js:125:0)
at module.exports.push../views/user/user-page.js.exports.onLoginPressed(file: app/views/user/user-page.js:84:0)
a<…>

Haven't figured how to solve this but recon that it isn't a major thing. If anybody got a suggestion as to how to solve this or know of another plugin with likewise functionality it'll be greatly appreciated, since it hinders us from releasing a new version of our app.

Archez commented 3 years ago

This is what I did in my app to make this plugin work with Nativescript 7 without having to modify the source files

In the webpack config I added a few alias records:

// webpack.config.js

// Shim old core modules view and text base to make nativescript-drop-down work with ns7
alias['ui/data/observable-array'] = resolve(projectRoot, 'shims/view.js');
alias['ui/core/view'] = resolve(projectRoot, 'shims/view.js');
alias['ui/text-base'] = resolve(projectRoot, 'shims/view.js');
alias['ui/editable-text-base/editable-text-base'] = resolve(projectRoot, `node_modules/${coreModulesPackageName}`, 'ui/editable-text-base');

The last alias just redirects the editable-text-base import one level up as Nativescript 7 switched to using index files. The others however point to a custom shim that I made to fix the remaining issues. The shim is as follows:

// shims/view.js

import { ObservableArray as _ObservableArray, Utils, View as _View } from '@nativescript/core';

// Export exepected properties
export {
  backgroundColorProperty,
  CoercibleProperty,
  colorProperty,
  CSSProperty,
  CSSType,
  fontInternalProperty,
  fontSizeProperty,
  Length,
  letterSpacingProperty,
  makeParser,
  makeValidator,
  paddingBottomProperty,
  paddingLeftProperty,
  paddingRightProperty,
  paddingTopProperty,
  Property,
  textAlignmentProperty,
  textDecorationProperty,
  textTransformProperty,
} from '@nativescript/core';

export const layout = Utils.layout;

// Wrap ES7 classes from Nativescript to be extendable from ES2015 prototypes

// Proxy the original ObservableArray class to embed an `apply` function
export const ObservableArray = new Proxy(_ObservableArray, {
  apply(target, thisArg, args) {
    // Create a dummy constructor to bind the `thisArg` prototype to
    function TempHelperConstructor() {
      //
    }

    // Override the prototype with the actual class that we want
    TempHelperConstructor.prototype = thisArg;

    // Reflect.construct allows us to call the class constructor without the `new` keyword
    // And enables us to change the `this` context
    return Reflect.construct(target, args, TempHelperConstructor);
  },
});

// Proxy the original View class
export const View = new Proxy(_View, {
  apply(target, thisArg, args) {
    function TempHelperConstructor() {
      //
    }

    TempHelperConstructor.prototype = thisArg;

    return Reflect.construct(target, args, TempHelperConstructor);
  },
});

There are two main goals this shim is accomplishing. The first is to reexport expected properties that pre-Nativescript 7 was exporting on almost every component. The second issue was dealing with the compiled plugin output (es2015) which is a Prototype based "class" that was extending an es6+ Class. I needed to handle both side stepping the new keyword requirement for construction, but also maintaining proper this context for extending.

This got the plugin working correctly for me on a Nativescript 7 project without touching the plugin source code.

Surely an update to this plugin to switch to ES7 would be ideal, but this works in the meantime ;)


Edit: Updated snippets to add support for the ValueList class

kryoware commented 3 years ago

@Archez your workaround saved my butt! I am building a free non-commercial app and I can't afford to subscribe for just this plugin (LOL)

Sorry to spring this on you, but have you encountered this error when using ValueList?

TypeError: Class constructor ObservableArray cannot be invoked without 'new'
schnapzz commented 3 years ago

Thanks a ton @Archez ! Haven't tried it out yet but appreciate the quick response. I'll see if I can get around testing it next week!

Archez commented 3 years ago

@kryoware

TypeError: Class constructor ObservableArray cannot be invoked without 'new'

It would be similar to what I did for the View class:

import { ObservableArray as _ObservableArray } from '@nativescript/core';

// Proxy the original ObservableArray
export const ObservableArray = new Proxy(_ObservableArray, {
  apply(target, thisArg, args) {
    function TempHelperConstructor() {
      //
    }

    TempHelperConstructor.prototype = thisArg;

    return Reflect.construct(target, args, TempHelperConstructor);
  },
});

And adding an alias record for it in webpack config

alias['ui/data/observable-array'] = resolve(projectRoot, 'shims/view.js');

So you can either throw it in the same shim, or separate it out if you want. I forgot I had created my own implementation of ValueList in my project and didn't hit this issue. (I haven't tested this out but should work 👍 )

schnapzz commented 3 years ago

This is what I did in my app to make this plugin work with Nativescript 7 without having to modify the source files

In the webpack config I added a few alias records:

// webpack.config.js

// Shim old core modules view and text base to make nativescript-drop-down work with ns7
alias['ui/data/observable-array'] = resolve(projectRoot, 'shims/view.js');
alias['ui/core/view'] = resolve(projectRoot, 'shims/view.js');
alias['ui/text-base'] = resolve(projectRoot, 'shims/view.js');
alias['ui/editable-text-base/editable-text-base'] = resolve(projectRoot, `node_modules/${coreModulesPackageName}`, 'ui/editable-text-base');

The last alias just redirects the editable-text-base import one level up as Nativescript 7 switched to using index files. The others however point to a custom shim that I made to fix the remaining issues. The shim is as follows:

// shims/view.js

import { ObservableArray as _ObservableArray, Utils, View as _View } from '@nativescript/core';

// Export exepected properties
export {
  backgroundColorProperty,
  CoercibleProperty,
  colorProperty,
  CSSProperty,
  CSSType,
  fontInternalProperty,
  fontSizeProperty,
  Length,
  letterSpacingProperty,
  makeParser,
  makeValidator,
  paddingBottomProperty,
  paddingLeftProperty,
  paddingRightProperty,
  paddingTopProperty,
  Property,
  textAlignmentProperty,
  textDecorationProperty,
  textTransformProperty,
} from '@nativescript/core';

export const layout = Utils.layout;

// Wrap ES7 classes from Nativescript to be extendable from ES2015 prototypes

// Proxy the original ObservableArray class to embed an `apply` function
export const ObservableArray = new Proxy(_ObservableArray, {
  apply(target, thisArg, args) {
    // Create a dummy constructor to bind the `thisArg` prototype to
    function TempHelperConstructor() {
      //
    }

    // Override the prototype with the actual class that we want
    TempHelperConstructor.prototype = thisArg;

    // Reflect.construct allows us to call the class constructor without the `new` keyword
    // And enables us to change the `this` context
    return Reflect.construct(target, args, TempHelperConstructor);
  },
});

// Proxy the original View class
export const View = new Proxy(_View, {
  apply(target, thisArg, args) {
    function TempHelperConstructor() {
      //
    }

    TempHelperConstructor.prototype = thisArg;

    return Reflect.construct(target, args, TempHelperConstructor);
  },
});

There are two main goals this shim is accomplishing. The first is to reexport expected properties that pre-Nativescript 7 was exporting on almost every component. The second issue was dealing with the compiled plugin output (es2015) which is a Prototype based "class" that was extending an es6+ Class. I needed to handle both side stepping the new keyword requirement for construction, but also maintaining proper this context for extending.

This got the plugin working correctly for me on a Nativescript 7 project without touching the plugin source code.

Surely an update to this plugin to switch to ES7 would be ideal, but this works in the meantime ;)

Edit: Updated snippets to add support for the ValueList class

To others who's not that strong with webpack and shims, I struggled to make it work until I realised the changes had to be done AFTER the following if statement:

    if (hasRootLevelScopedModules) {
        coreModulesPackageName = "@nativescript/core";
        alias["tns-core-modules"] = coreModulesPackageName;
    }

Thanks again @Archez for the neat workaround!

ReazerDev commented 3 years ago

@PeterStaev Hi, I'm trying to update the plugin to NS7 right now, but I'm having some problems. In the drop-down.ios.ts file, you are importing stuff like Length, backgroundColorProperty, etc. from drop-down-common, but these properties/members don't exist there. Did you remove something from the code on GitHub?

PeterStaev commented 3 years ago

@ReazerDev , I have not removed anything. Whatever is in GH is the latest working version that is available on NPM. The missing properties are coming from the re-export of view: https://github.com/PeterStaev/NativeScript-Drop-Down/blob/8aed0a461ab62dafcabd9dff2c1c483784442d34/drop-down-common.ts#L24

ReazerDev commented 3 years ago

Hi, @PeterStaev I'm kinda stuck^^ Would you be willing to help a little? The demo app is installing fine, but once the view is being rendered, I get this error: image

My current status is in my branch

PeterStaev commented 3 years ago

@ReazerDev , you will have to rewrite the way the angular code is compiled. The one that was used in pre-NS6 is NOT compatible with Angular Ivy (Angular 9+).

I would suggest first getting the non-NG demo working and then see how to fix the Angular component.

ReazerDev commented 3 years ago

Ok nice, done :) Both the normal demo and the ng demo work on android now!

It'd be awesome if someone could test it on iOS. I don't own any apple devices lol

OPADA-Eng commented 3 years ago

Any updates on this?

ReazerDev commented 3 years ago

Any updates on this?

@OPADA-Eng Just a small problem on android, that I have to fix. Tho I won't be able to work on it, til Wednesday, got an exam coming up.

OPADA-Eng commented 3 years ago

@ReazerDev Thanks for your efforts and good luck in your exam.

OPADA-Eng commented 3 years ago

Any news @ReazerDev? I have to deploy my app so this plugin is breaking it, and I have to decide deployment with or without it.

ReazerDev commented 3 years ago

@OPADA-Eng You can see the current status here: https://github.com/PeterStaev/NativeScript-Drop-Down/pull/257