博客 页面 5

ionic Native插件封装

在项目升级到ionic5/angular9后,发现部分cordova插件用不了了。

添加ngzone.run后解决了部分插件的报错。

猜测是ivy编译造成,最好的解决办法还是按ionic标准封装cordova插件。

ionic Native插件本质上是对cordova插件的封装,其不实现功能,更多的只是提供ts和ngx的支持。

官方文档

1.创建插件封装器

First, let’s start by creating a new plugin wrapper from template.

// Call this command, and replace PluginName with the name of the plugin you wish to add
// Make sure to capitalize the first letter, or use CamelCase if necessary.

gulp plugin:create -n PluginName

// add -m flag to get a minimal template to start with
gulp plugin:create -m -n PluginName

Running the command above will create a new directory src/@ionic-native/plugins/plugin-name/ with a single file in there: index.ts. This file is where all the plugin definitions should be.

Let’s take a look at the existing plugin wrapper for Geolocation to see what goes into an Ionic Native plugin (comments have been removed for clarity):

@Plugin({
  plugin: 'cordova-plugin-geolocation',
  pluginRef: 'navigator.geolocation'
})
@Injectable()
export class Geolocation {

  @Cordova()
  getCurrentPosition(options?: GeolocationOptions): Promise<Geoposition> { return; }

  @Cordova({
    callbackOrder: 'reverse',
    observable: true,
    clearFunction: 'clearWatch'
  })
  watchPosition(options?: GeolocationOptions): Observable<Geoposition> { return; }
}

First and foremost, we want to create a class representing our plugin, in this case Geolocation.

@Injectable()
class Geolocation {

}

Class Metadata

Next, we need to specify some information about this plugin. Ionic Native is written in TypeScript and makes use of a feature called decorators. Long story short, decorators allow us to modify or add info to classes and properties using a declarative syntax.

For example, the @Plugin decorator adds information about the plugin to our Geolocation class:

@Plugin({
  plugin: 'cordova-plugin-geolocation',
  pluginRef: 'navigator.geolocation'
})
@Injectable()
export class Geolocation {

}

Here, plugin is the name of the plugin package on npm and used when calling cordova plugin add.

pluginRef refers to the where on window the underlying Cordova plugin is normally exposed. For example, in the case of the Cordova Geolocation plugin, normally you would make calls like window.navigator.geolocation.getCurrentPosition({}, success, error), so the pluginRef in this case is navigator.geolocation.

Class Methods

Now all that’s left is to add the plugin methods, in this case getCurrentPosition and watchPosition.

Let’s take a look at getCurrentPosition first.

  @Cordova()
  getCurrentPosition(options?: GeolocationOptions): Promise<Geoposition> { return }

It’s just a stub. The return is only there to keep the TypeScript type-checker from complaining since we indicate that getCurrentPosition returns a Promise<Geoposition>.

By default, the @Cordova decorator wraps the plugin callbacks in a Promise that resolves when the success callback is called and rejects when the error callback is called. It also ensures that Cordova and the underlying plugin are available, and prints helpful diagnostics if they aren’t.

Next, let’s look at the watchPosition method.

  @Cordova({
    callbackOrder: 'reverse',
    observable: true,
    clearFunction: 'clearWatch'
  })
  watchPosition(options?: GeolocationOptions): Observable<Geoposition> { return }

The @Cordova decorator has a few more options now.

observable indicates that this method may call its callbacks multiple times, so @Cordova wraps it in an Observable instead of a Promise.

callbackOrder refers to the method signature of the underlying Cordova plugin, and tells Ionic Native which arguments are the callbacks to map to the wrapping Promise or Observable. In this case, the signature is watchPosition(success, error, options), so we need to tell @Cordova that the callbacks are the first arguments, not the last arguments. For rare cases, you can also specify the options successIndex and errorIndex to indicate where in the argument list the callbacks are located.

clearFunction is used in conjunction with the observable option and indicates the function to be called when the Observable is disposed.

Testing your changes

You need to run npm run build in the ionic-native project, this will create a dist directory. The dist directory will contain a sub directory @ionic-native with all the packages compiled in there. Copy the package(s) you created/modified to your app’s node_modules under the @ionic-native directory. (e.g. cp -r dist/@ionic-native/plugin-name ../my-app/node_modules/@ionic-native/).

Cleaning the code

You need to run npm run lint to analyze the code and ensure its consistency with the repository style. Fix any errors before submitting a PR.

‘Wrapping’ Up

That’s it! The only thing left to do is rigorously document the plugin and its usage. Take a look at some of the other plugins for good documentation styles.

Commit Message Format

We have very precise rules over how our git commit messages can be formatted. This leads to more readable messages that are easy to follow when looking through the project history. But also, we use the git commit messages to generate the our change log. (Ok you got us, it’s basically Angular’s commit message format).

type(scope): subject

Type

Must be one of the following:

  • fix: A bug fix
  • feat: A new feature
  • docs: Documentation only changes
  • style: Changes that do not affect the meaning of the code (white-space, formatting, missing semi-colons, etc)
  • refactor: A code change that neither fixes a bug nor adds a feature
  • perf: A code change that improves performance
  • test: Adding missing tests
  • chore: Changes to the build process or auxiliary tools and libraries such as documentation generation

Scope

The scope could be anything specifying place of the commit change. For example, the name of the plugin being changed

Subject

The subject contains succinct description of the change:

  • use the imperative, present tense: “change” not “changed” nor “changes”
  • do not capitalize first letter
  • do not place a period (.) at the end
  • entire length of the commit message must not go over 50 characters

Ionic Native Decorators

Plugin

A decorator to wrap the main plugin class, and any other classes that will use @Cordova or @CordovaProperty decorators. This decorator accepts the following configuration:

  • pluginName: Plugin name, this should match the class name
  • plugin: The plugin’s NPM package, or Github URL if NPM is not available.
  • pluginRef: The plugin object reference. Example: ‘cordova.file’.
  • repo: The plugin’s Github Repository URL
  • install: (optional) Install command. This is used in case a plugin has a custom install command (takes variables).
  • platforms: An array of strings indicating the supported platforms.

Cordova

Checks if the plugin and the method are available before executing. By default, the decorator will wrap the callbacks of the function and return a Promise. This decorator takes the following configuration options:

  • observable: set to true to return an Observable
  • clearFunction: an optional name of a method to clear the observable we returned
  • clearWithArgs: This can be used if clearFunction is set. Set this to true to call the clearFunction with the same arguments used in the initial function.
  • sync: set to true if the method should return the value as-is without wrapping with Observable/Promise
  • callbackOrder: set to reverse if the success and error callbacks are the first two arguements of the method
  • callbackStyle: set to node if the plugin has one callback with a node style (e.g: function(err, result){}), or set to object if the callbacks are part of an object
  • successName: Success function property name. This must be set if callbackStyle is set to object.
  • errorName: Error function property name. This must be set if callbackStyle is set to object.
  • successIndex: Set a custom index for the success callback function. This doesn’t work if callbackOrder or callbackStyle are set.
  • errorIndex: Set a custom index for the error callback function. This doesn’t work if callbackOrder or callbackStyle are set.
  • eventObservable: set to true to return an observable that wraps an event listener
  • event: Event name, this must be set if eventObservable is set to true
  • element: Element to attach the event listener to, this is optional, defaults to window
  • otherPromise: Set to true if the wrapped method returns a promise
  • platforms: array of strings indicating supported platforms. Specify this if the supported platforms doesn’t match the plugin’s supported platforms.

Example:

@Cordova()
someMethod(): Promise<any> { return; }

@Cordova({ sync: true })
syncMethod(): number { }

CordovaProperty

Checks if the plugin and property exist before getting/setting the property’s value

Example:

@CordovaProperty()
someProperty: string;

CordovaCheck

Checks if the plugin exists before performing a custom written method. By default, the method will return a promise that will reject with an error if the plugin is not available. This wrapper accepts two optional configurations:

  • observable: set to true to return an empty Observable if the plugin isn’t available
  • sync: set to true to return nothing if the plugin isn’t available

Example:

@CordovaCheck()
someMethod(): Promise<any> {
  // anything here will only run if the plugin is available
}

CordovaFunctionOverride

Wrap a stub function in a call to a Cordova plugin, checking if both Cordova and the required plugin are installed.

Example:

@CordovaFunctionOverride()
someMethod(): Observable<any> { return; }

deno与ts-node的区别

Deno is more like Node than like ts-node, i.e. it is a JS runtime based on V8. Unlike Node, Deno contains the TypeScript compiler. Deno is not part of the Node/npm ecosystem.

ts-node on the other hand is a Node.js module that uses the TypeScript compiler to transpile TypeScript code and run it in Node. ts-node is part of the Node/npm ecosystem.

Deno is fast. See below.

Deno and ts-node similarities

  • They both run TypeScript code
  • They both run on Linux, Mac and Windows (but ts-node also on SmartOS and AIX)
  • They both use the Google V8 JavaScript engine (ts-node via node that it uses under the hood)

Deno and ts-node differences

ts-node

  • ts-node is a Node.js module
  • it is written in Node.js
  • it’s installed with npm
  • it uses the TypeScript compiler as a peer dependency
  • it installs its own dependencies
  • as a runtime it uses Node which is written in C++ using libuv

Deno

  • deno is a standalone executable
  • it doesn’t use Node.js
  • it is distributed as a single binary
  • it contains the TypeScript compiler as a V8 snapshot
  • it has no dependencies
  • it is a runtime written in Rust using Tokio

Maturity

ts-node

ts-node relies on the Node.js runtime so it is fair to include it here:

  • Node.js was released in 2009, the latest LTS version is 10.15.3
  • npm was released in 2010, version included in Node LTS is 6.4.1
  • ts-node was released in 2015, the latest version is 8.0.3

Deno

Deno is itself a runtime so it doesn’t use anything else:

  • Deno was released in 2018, the latest version is 0.3.6

Popularity

GitHub:

Stack Overflow:

Libraries

ts-node

You can use all Node libraries available on npm

(currently there are 955,263 packages on npm, not all of them for Node but still a lot)

The Node libraries that are available on npm even if they were originally written in TypeScript are usually published in a form transpiled to JavaScript with additional type definitions in *.d.ts files (included in the npm package or installed separately from the @types namespace).

Deno

There are 55 third-party modules on https://deno.land/x/ and 56 libraries and tools on https://github.com/denolib/awesome-deno#modules (I didn’t check if all are the same)

The Deno libraries are just TypeScript files.

Installation difference

ts-node

  • you install Node.js
  • you install typescript and ts-node with their dependencies with npm
    • npm install typescript ts-node
    • it installs 10 npm modules and puts 44MB in 212 files into node_modules

Deno

Your code differences

ts-node

  • your code works the same as if it were transpiled with tsc and run with node (because it is under the hood)
  • you can use the Node API
  • you can use all built-in Node modules
  • you can use modules from npm
  • you can import files using relative paths (usually without .ts suffix)
  • you can import the dependencies installed with npm (or yarn) in node_modules

Deno

  • your code doesn’t work the same as in Node (because it isn’t run with Node)
  • you use the Deno API
  • you can use the Deno built-in modules
  • you can use other Deno modules that are available
  • you can import files using relative paths (always with .ts suffix!)
  • you can import URLs directly from the Web (no need for npm install)

Examples

Here is an example of publishing a minimal library written in TypeScript and using it.

Creating and using a TypeScript library with Node and ts-node

This is what I am doing right now with an example project on:

https://github.com/rsp/node-ts-hello

Creating library:

  1. find a name that is free on npm (no longer enough, see below)
  2. create repo on GitHub
  3. create package.json with npm init
  4. install TypeScript compiler with npm install typescript
  5. decide if you’re keeping package-lock.json in the repo (there are pros and cons)
  6. create a src dir where you will keep TypeScript files
  7. add hello.ts to src
  8. add tsconfig.json file and make sure to:
    • add "src/**/*" to "include"
    • add dependencies and your own types to "paths"
    • add "outDir": "dist" to put the JS files in a known place
    • add the dist directory to .gitignore so that compiled files are not in git
    • add the same as in .gitignore but without dist in .npmignore
      (or otherwise you will not publish the most important files, see below)
    • add "declaration": true so you have *.d.ts files generated
  9. add "main": "dist/hello.js" in package.json (note the “js” suffix)
  10. add "types": "dist/hello.d.ts" in package.json (note the “ts” suffix)
  11. add "build": "tsc" to package.json (watch out for redundant files, see below)
  12. login with npm login (you shouldn’t be logged in all the time – see: Now Pushing Malware: NPM package dev logins slurped by hacked tool popular with coders)
  13. compile the project with npm run build
  14. publish the package with npm publish
    • when you get npm ERR! publish Failed PUT 401 you need to login with npm login
    • when you get npm ERR! publish Failed PUT 403 your package may be “too similar to existing packages” – try renaming it in package.json, rename the repo and update all liks to readme, issues itp. in package.json
  15. logout from npm with npm logout
  16. see your ~/.npmrc and make sure you have nothing like this left:
    • //registry.npmjs.org/:_authToken=...

Using the library in other project using ts-node

  1. create a new directory
  2. create a package.json file with npm init
    • (so that you can install dependencies locally for your new program)
  3. install our library with npm install node-ts-hello
  4. optionally install ts-node with npm install typescript ts-node
    • (unless it’s installed globally)
  5. add hi.ts file that imports our library with:
    • import { hello } from 'node-ts-hello';
    • hello('TS');
  6. run it with npx ts-node hi.ts (if ts-node was installed locally) or ts-node hi.ts (if ts-node was installed globally)
    • if you get errors, see below

Potential problems: I simplified the above a little bit, my actual process of creating that library is described here.

Creating and using a TypeScript library with Deno

This is what I am doing right now with an example project on:

https://github.com/rsp/deno-hello

Creating library:

  1. create repo on GitHub
  2. put hello.ts in the repo

Using library:

  1. Create a file hi.ts with the contents:
    • import { hello } from 'https://raw.githubusercontent.com/rsp/deno-hello/master/hello.ts';
    • hello('TS');
  2. Run your program with deno run hi.ts

The first run will print:

$ deno run hi.ts 
Compiling file:///Users/rsp/talks/deno/hello-deno-test/hi.ts
Downloading https://raw.githubusercontent.com/rsp/deno-hello/master/hello.ts
Compiling https://raw.githubusercontent.com/rsp/deno-hello/master/hello.ts
Hello, TS!

The second run:

$ deno run hi.ts 
Hello, TS!

If you change hi.ts it will be recompiled but the dependencies will not get downloaded again:

$ deno run hi.ts 
Compiling file:///Users/rsp/talks/deno/hello-deno-test/hi.ts
Hello, TS!

(Note that touch hi.ts will not be enough, you need to make the actual changes because Deno checks the file checksum, not the timestamp.)

Speed

ts-node

The speed of starting the ts-node version of our hi.ts from the examples above:

$ time npx ts-node hi.ts 
Hello, TS!

real    0m0.904s
user    0m1.300s
sys     0m0.083s

This is after the dependencies are already installed and after running several times to make sure that all of the caching works. Almost one second.

Deno

The speed of starting the Deno version of our hi.ts from the examples above:

$ time deno run hi.ts 
Hello, TS!

real    0m0.028s
user    0m0.010s
sys     0m0.015s

This is also after the dependencies are already installed and after running several times to make sure that all of the caching works.

More than 32x speed improvement.

Summary

Deno should be compared more with Node than with ts-node because Deno is an entirely new runtime while ts-node is a module for Node so your program run with ts-node really use the Node runtime.

It is a very young project but has already got a lot of traction. It doesn’t have as much documentation or libraries as Node but it means that it may be the best time to get involved because when it gets more popular, and I think it will for many reasons that are beyond the scope of this answer, people who already have experience with it will be needed on the market, like it was with Node.

The program startup speed is already very impressive and I expect more improvements there.

The development speed of using single files with no need for configuration like package.json or node_modules together with a possibility to import dependencies directly from URLs (like on the frontend) will make it possible to work in a different way both for the end user code and for the libraries. We’ll see how it all works in practice but it already looks promising.

原文 https://stackoverflow.com/questions/53428120/deno-vs-ts-node-whats-the-difference

编写了一道逻辑题

单选题,请听题:

夏天到了,你居住的小区垃圾处理不及时,垃圾房外爬蛆飞苍蝇了,你在业主群说物业管理垃圾的人处理的不好。
然后出来了几个业主代表艾特你。
业主甲:虽然我们小区垃圾回收做的不好,但安全啊,至今没有发生过盗窃,谢谢物业人员?。
业主乙:隔壁小区管理的更烂,你看他们垃圾一月才处理一次,所以我们小区很好了?。
业主丙:你经常说我们小区不好,你就是恨我们小区,不喜欢我们小区,就滚去别的小区买房子啊?。
业主丁:觉得物业不好,就去应聘物业,加入他们,让物业变得更好?。

问,哪个业主可以代表你?

微前端解决方案

去年就在进行一些微前端工作,现在重新整理下相关方案以供选择:

乾坤qiankun

https://github.com/umijs/qiankun

介绍: https://zhuanlan.zhihu.com/p/78362028

single-spa

https://single-spa.js.org/

飞冰 icestark

https://github.com/ice-lab/icestark

mooa

https://github.com/phodal/mooa

介绍:

ngx-planet

https://github.com/worktile/ngx-planet

介绍: https://zhuanlan.zhihu.com/p/93813936

angular8应用在IOS10中白屏

解决办法:

将polyfills.ts中的

import ‘zone.js/dist/zone’;

放到

main.ts中