LongYinan 5 年之前
父节点
当前提交
fb1b1dea3b
共有 22 个文件被更改,包括 3195 次插入0 次删除
  1. 183 0
      .github/workflows/CI.yml
  2. 122 0
      .gitignore
  3. 24 0
      Cargo.toml
  4. 46 0
      README.md
  5. 14 0
      __test__/index.spec.js
  6. 5 0
      build.rs
  7. 3 0
      index.d.ts
  8. 14 0
      index.js
  9. 3 0
      npm/darwin/README.md
  10. 16 0
      npm/darwin/package.json
  11. 3 0
      npm/linux/README.md
  12. 16 0
      npm/linux/package.json
  13. 3 0
      npm/win32/README.md
  14. 16 0
      npm/win32/package.json
  15. 59 0
      package.json
  16. 1 0
      scripts/platforms.js
  17. 27 0
      scripts/publish.js
  18. 6 0
      scripts/update-package.js
  19. 39 0
      scripts/upload-to-release.js
  20. 17 0
      scripts/version.js
  21. 53 0
      src/lib.rs
  22. 2525 0
      yarn.lock

+ 183 - 0
.github/workflows/CI.yml

@@ -0,0 +1,183 @@
+name: CI
+
+on:
+  push:
+    branches:
+      - '**'
+    tags-ignore:
+      - '**'
+  pull_request:
+    branches:
+      - '**'
+
+jobs:
+  build:
+    if: "!contains(github.event.head_commit.message, 'skip ci')"
+
+    strategy:
+      fail-fast: false
+      matrix:
+        os: [ubuntu-latest, macos-latest, windows-latest]
+
+    name: stable - ${{ matrix.os }} - node@12
+    runs-on: ${{ matrix.os }}
+
+    steps:
+      - uses: actions/checkout@v2
+
+      - name: Setup node
+        uses: actions/setup-node@v1
+        with:
+          node-version: 12
+
+      - name: Set platform name
+        run: |
+          export NODE_PLATFORM_NAME=$(node -e "console.log(require('os').platform())")
+          echo "::set-env name=PLATFORM_NAME::$NODE_PLATFORM_NAME"
+        shell: bash
+
+      - name: Install llvm
+        if: matrix.os == 'windows-latest'
+        run: choco install -y llvm
+
+      - name: Set llvm path
+        if: matrix.os == 'windows-latest'
+        uses: allenevans/set-env@v1.0.0
+        with:
+          LIBCLANG_PATH: 'C:\\Program Files\\LLVM\\bin'
+
+      - name: Install
+        uses: actions-rs/toolchain@v1
+        with:
+          toolchain: stable
+          profile: minimal
+          override: true
+
+      - name: Generate Cargo.lock
+        uses: actions-rs/cargo@v1
+        with:
+          command: generate-lockfile
+
+      - name: Cache cargo registry
+        uses: actions/cache@v1
+        with:
+          path: ~/.cargo/registry
+          key: stable-${{ matrix.os }}-node@12-cargo-registry-trimmed-${{ hashFiles('**/Cargo.lock') }}
+
+      - name: Cache cargo index
+        uses: actions/cache@v1
+        with:
+          path: ~/.cargo/git
+          key: stable-${{ matrix.os }}gnu-node@12-cargo-index-trimmed-${{ hashFiles('**/Cargo.lock') }}
+
+      - name: Cache NPM dependencies
+        uses: actions/cache@v1
+        with:
+          path: node_modules
+          key: npm-cache-${{ matrix.os }}-node@12-${{ hashFiles('yarn.lock') }}
+          restore-keys: |
+            npm-cache-
+      - name: 'Install dependencies'
+        run: yarn install --frozen-lockfile --registry https://registry.npmjs.org
+
+      - name: 'Build'
+        run: yarn build
+
+      - name: Upload artifact
+        uses: actions/upload-artifact@v2
+        with:
+          name: bindings-${{ env.PLATFORM_NAME }}
+          path: index.${{ env.PLATFORM_NAME }}.node
+
+      - name: Clear the cargo caches
+        run: |
+          cargo install cargo-cache --no-default-features --features ci-autoclean
+          cargo-cache
+
+  test_binding:
+    name: Test bindings on ${{ matrix.os }} - node@${{ matrix.node }}
+    needs:
+      - build
+    strategy:
+      fail-fast: false
+      matrix:
+        os: [ubuntu-latest, macos-latest, windows-latest]
+        node: ['10', '12', '14']
+    runs-on: ${{ matrix.os }}
+
+    steps:
+      - uses: actions/checkout@v2
+
+      - name: Setup node
+        uses: actions/setup-node@v1
+        with:
+          node-version: ${{ matrix.node }}
+
+      - name: Set platform name
+        run: |
+          export NODE_PLATFORM_NAME=$(node -e "console.log(require('os').platform())")
+          echo "::set-env name=PLATFORM_NAME::$NODE_PLATFORM_NAME"
+        shell: bash
+
+      # Do not cache node_modules, or yarn workspace links broken
+      - name: 'Install dependencies'
+        run: yarn install --frozen-lockfile --registry https://registry.npmjs.org
+
+      - name: Download artifacts
+        uses: actions/download-artifact@v2
+        with:
+          name: bindings-${{ env.PLATFORM_NAME }}
+          path: .
+
+      - name: List packages
+        run: ls -R .
+        shell: bash
+
+      - name: Test bindings
+        run: yarn test
+
+  publish:
+    name: Publish
+    if: "startsWith(github.event.head_commit.message, 'chore(release): publish')"
+    runs-on: ubuntu-latest
+    needs: test_binding
+
+    steps:
+      - uses: actions/checkout@v2
+
+      - name: Setup node
+        uses: actions/setup-node@v1
+        with:
+          node-version: 12
+
+      - name: Cache NPM dependencies
+        uses: actions/cache@v1
+        with:
+          path: node_modules
+          key: npm-cache-ubuntu-latest-${{ hashFiles('yarn.lock') }}
+          restore-keys: |
+            npm-cache-
+      - name: 'Install dependencies'
+        run: yarn install --frozen-lockfile --registry https://registry.npmjs.org
+
+      - name: Download all artifacts
+        uses: actions/download-artifact@v2
+        with:
+          path: .
+
+      - name: List packages
+        run: ls -R .
+        shell: bash
+
+      - name: Upload artifacts to Github release
+        run: |
+          node ./upload-to-release.js
+        env:
+          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+
+      - name: Lerna publish
+        run: |
+          echo "//registry.npmjs.org/:_authToken=$NPM_TOKEN" >> ~/.npmrc
+          npm publish
+        env:
+          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}

+ 122 - 0
.gitignore

@@ -0,0 +1,122 @@
+
+# Created by https://www.toptal.com/developers/gitignore/api/node
+# Edit at https://www.toptal.com/developers/gitignore?templates=node
+
+### Node ###
+# Logs
+logs
+*.log
+npm-debug.log*
+yarn-debug.log*
+yarn-error.log*
+lerna-debug.log*
+
+# Diagnostic reports (https://nodejs.org/api/report.html)
+report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json
+
+# Runtime data
+pids
+*.pid
+*.seed
+*.pid.lock
+
+# Directory for instrumented libs generated by jscoverage/JSCover
+lib-cov
+
+# Coverage directory used by tools like istanbul
+coverage
+*.lcov
+
+# nyc test coverage
+.nyc_output
+
+# Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files)
+.grunt
+
+# Bower dependency directory (https://bower.io/)
+bower_components
+
+# node-waf configuration
+.lock-wscript
+
+# Compiled binary addons (https://nodejs.org/api/addons.html)
+build/Release
+
+# Dependency directories
+node_modules/
+jspm_packages/
+
+# TypeScript v1 declaration files
+typings/
+
+# TypeScript cache
+*.tsbuildinfo
+
+# Optional npm cache directory
+.npm
+
+# Optional eslint cache
+.eslintcache
+
+# Microbundle cache
+.rpt2_cache/
+.rts2_cache_cjs/
+.rts2_cache_es/
+.rts2_cache_umd/
+
+# Optional REPL history
+.node_repl_history
+
+# Output of 'npm pack'
+*.tgz
+
+# Yarn Integrity file
+.yarn-integrity
+
+# dotenv environment variables file
+.env
+.env.test
+
+# parcel-bundler cache (https://parceljs.org/)
+.cache
+
+# Next.js build output
+.next
+
+# Nuxt.js build / generate output
+.nuxt
+dist
+
+# Gatsby files
+.cache/
+# Comment in the public line in if your project uses Gatsby and not Next.js
+# https://nextjs.org/blog/next-9-1#public-directory-support
+# public
+
+# vuepress build output
+.vuepress/dist
+
+# Serverless directories
+.serverless/
+
+# FuseBox cache
+.fusebox/
+
+# DynamoDB Local files
+.dynamodb/
+
+# TernJS port file
+.tern-port
+
+# Stores VSCode versions used for testing VSCode extensions
+.vscode-test
+
+# End of https://www.toptal.com/developers/gitignore/api/node
+
+
+#Added by cargo
+
+/target
+Cargo.lock
+
+*.node

+ 24 - 0
Cargo.toml

@@ -0,0 +1,24 @@
+[package]
+name = "napi-package-template"
+version = "0.1.0"
+authors = ["LongYinan <lynweklm@gmail.com>"]
+edition = "2018"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[lib]
+crate-type = ["cdylib"]
+
+[dependencies]
+napi = { version = "0.4" }
+napi-derive = { version = "0.4" }
+
+[target.'cfg(all(unix, not(target_env = "musl")))'.dependencies]
+jemallocator = { version = "0.3", features = ["disable_initial_exec_tls"] }
+
+[build-dependencies]
+napi-build = "0.2"
+
+[profile.release]
+opt-level = 3
+lto = true

+ 46 - 0
README.md

@@ -0,0 +1,46 @@
+# `@napi-rs/package-template`
+
+![https://github.com/napi-rs/package-template/actions](https://github.com/napi-rs/package-template/workflows/CI/badge.svg)
+
+> Template project for writing node package with napi-rs.
+
+## Requirement
+
+- Install latest `Rust`
+- Install `NodeJS@8.9+` which supported `N-API`
+- Install `yarn@1.x`
+
+## Test in local
+
+- yarn
+- yarn build
+- yarn test
+
+And you will see:
+
+```bash
+$ ava --verbose
+
+  ✔ sync function from native code
+  ✔ sleep function from native code (201ms)
+  ─
+
+  2 tests passed
+✨  Done in 1.12s.
+```
+
+## Release package
+
+Ensure you have set you **NPM_TOKEN** in `Github` project setting.
+
+In `Settings -> Secrets`, add **NPM_TOKEN** into it.
+
+When you want release package:
+
+```
+yarn version [xxx]
+
+git push --follow-tags
+```
+
+Github actions will do the rest job for you.

+ 14 - 0
__test__/index.spec.js

@@ -0,0 +1,14 @@
+const test = require('ava')
+
+const { sleep, sync } = require('../index')
+
+test('sync function from native code', (t) => {
+  const fixture = 42
+  t.is(sync(fixture), fixture + 100)
+})
+
+test('sleep function from native code', async (t) => {
+  const timeToSleep = 200
+  const value = await sleep(timeToSleep)
+  t.is(value, timeToSleep * 2)
+})

+ 5 - 0
build.rs

@@ -0,0 +1,5 @@
+extern crate napi_build;
+
+fn main() {
+  napi_build::setup();
+}

+ 3 - 0
index.d.ts

@@ -0,0 +1,3 @@
+export const sync: (input: number) => number
+// sleep [duration] ms, return Promise which resolved 2 * duration
+export const sleep: (duration: number) => Promise<number>

+ 14 - 0
index.js

@@ -0,0 +1,14 @@
+const { loadBinding } = require('@node-rs/helper')
+
+try {
+  // __dirname means load native addon from current dir
+  // 'index' means native addon name is `index`
+  // the value of this two arguments was decided by `build` script in `package.json`
+  module.exports = loadBinding(__dirname, 'index')
+} catch (e) {
+  try {
+    module.exports = require(`@swc-node/core-${platform()}`)
+  } catch (e) {
+    throw new TypeError('Not compatible with your platform. Error message: ' + e.message)
+  }
+}

+ 3 - 0
npm/darwin/README.md

@@ -0,0 +1,3 @@
+# `@napi-rs/package-template-darwin`
+
+This is the macOS 64-bit binary for `@napi-rs/package-template`.

+ 16 - 0
npm/darwin/package.json

@@ -0,0 +1,16 @@
+{
+  "name": "@napi-rs/package-template-darwin",
+  "version": "0.0.0",
+  "description": "Template project for writing node package with napi-rs",
+  "repository": "git@github.com:napi-rs/package-template.git",
+  "license": "MIT",
+  "keywords": ["napi-rs", "NAPI", "N-API", "Rust", "node-addon", "node-addon-api"],
+  "main": "index.darwin.node",
+  "files": ["index.darwin.node"],
+  "publishConfig": {
+    "registry": "https://registry.npmjs.org/",
+    "access": "public"
+  },
+  "os": ["darwin"],
+  "cpu": ["x64"]
+}

+ 3 - 0
npm/linux/README.md

@@ -0,0 +1,3 @@
+# `@napi-rs/package-template-linux`
+
+This is the Linux 64-bit binary for `@napi-rs/package-template`.

+ 16 - 0
npm/linux/package.json

@@ -0,0 +1,16 @@
+{
+  "name": "@napi-rs/package-template-linux",
+  "version": "0.0.0",
+  "description": "Template project for writing node package with napi-rs",
+  "repository": "git@github.com:napi-rs/package-template.git",
+  "license": "MIT",
+  "keywords": ["napi-rs", "NAPI", "N-API", "Rust", "node-addon", "node-addon-api"],
+  "main": "index.linux.node",
+  "files": ["index.linux.node"],
+  "publishConfig": {
+    "registry": "https://registry.npmjs.org/",
+    "access": "public"
+  },
+  "os": ["linux"],
+  "cpu": ["x64"]
+}

+ 3 - 0
npm/win32/README.md

@@ -0,0 +1,3 @@
+# `@napi-rs/package-template-win32`
+
+This is the Windows 64-bit binary for `@napi-rs/package-template`.

+ 16 - 0
npm/win32/package.json

@@ -0,0 +1,16 @@
+{
+  "name": "@napi-rs/package-template-win32",
+  "version": "0.0.0",
+  "description": "Template project for writing node package with napi-rs",
+  "repository": "git@github.com:napi-rs/package-template.git",
+  "license": "MIT",
+  "keywords": ["napi-rs", "NAPI", "N-API", "Rust", "node-addon", "node-addon-api"],
+  "main": "index.win32.node",
+  "files": ["index.win32.node"],
+  "publishConfig": {
+    "registry": "https://registry.npmjs.org/",
+    "access": "public"
+  },
+  "os": ["win32"],
+  "cpu": ["x64"]
+}

+ 59 - 0
package.json

@@ -0,0 +1,59 @@
+{
+  "name": "@napi-rs/package-template",
+  "version": "0.0.0",
+  "description": "Template project for writing node package with napi-rs",
+  "main": "index.js",
+  "repository": "git@github.com:napi-rs/package-template.git",
+  "license": "MIT",
+  "keywords": ["napi-rs", "NAPI", "N-API", "Rust", "node-addon", "node-addon-api"],
+  "files": ["index.d.ts", "index.js"],
+  "os": ["darwin", "linux", "win32"],
+  "cpu": ["x64"],
+  "engines": {
+    "node": ">= 8.9"
+  },
+  "publishConfig": {
+    "registry": "https://registry.npmjs.org/",
+    "access": "public"
+  },
+  "scripts": {
+    "build": "cargo build --release && napi --platform --release ./index",
+    "build:debug": "cargo build && napi --platform ./index",
+    "prepublish": "node ./scripts/publish.js",
+    "test": "ava",
+    "version": "node ./scripts/version.js"
+  },
+  "devDependencies": {
+    "@octokit/rest": "^18.0.3",
+    "ava": "^3.11.1",
+    "chalk": "^4.1.0",
+    "husky": "^4.2.5",
+    "lint-staged": "^10.2.11",
+    "napi-rs": "^0.2.4",
+    "prettier": "^2.0.5",
+    "putasset": "^5.0.3",
+    "typescript": "^3.9.7"
+  },
+  "dependencies": {
+    "@node-rs/helper": "^0.2.1"
+  },
+  "lint-staged": {
+    "*.@(js|ts|tsx)": ["prettier --write"],
+    "*.@(yml|yaml)": ["prettier --parser yaml --write"],
+    "*.md": ["prettier --parser markdown --write"],
+    "*.json": ["prettier --parser json --write"]
+  },
+  "prettier": {
+    "printWidth": 120,
+    "semi": false,
+    "trailingComma": "all",
+    "singleQuote": true,
+    "arrowParens": "always",
+    "parser": "typescript"
+  },
+  "husky": {
+    "hooks": {
+      "pre-commit": "lint-staged"
+    }
+  }
+}

+ 1 - 0
scripts/platforms.js

@@ -0,0 +1 @@
+module.exports = ['darwin', 'linux', 'win32']

+ 27 - 0
scripts/publish.js

@@ -0,0 +1,27 @@
+const { execSync } = require('child_process')
+const fs = require('fs')
+const path = require('path')
+
+const platforms = require('./platforms')
+const updatePackageJson = require('./update-package')
+
+const { version } = require('../package.json')
+
+updatePackageJson(path.join(__dirname, '..', 'package.json'), {
+  optionalDependencies: platforms.reduce((acc, cur) => {
+    acc[`@napi-rs/package-template-${cur}`] = `^${version}`
+    return acc
+  }, {}),
+})
+
+for (const name of platforms) {
+  const pkgDir = path.join(__dirname, '..', 'npm', name)
+  const filename = `index.${name}.node`
+  const bindingFile = fs.readFileSync(path.join(__dirname, '..', `bindings-${name}`, filename))
+  fs.writeFileSync(path.join(pkgDir, filename), bindingFile)
+  execSync('npm publish', {
+    cwd: pkgDir,
+    env: process.env,
+    stdio: 'inherit',
+  })
+}

+ 6 - 0
scripts/update-package.js

@@ -0,0 +1,6 @@
+const fs = require('fs')
+
+module.exports = function updatePackageJson(path, partial) {
+  const old = require(path)
+  fs.writeFileSync(path, JSON.stringify({ ...old, ...partial }, null, 2))
+}

+ 39 - 0
scripts/upload-to-release.js

@@ -0,0 +1,39 @@
+const { execSync } = require('child_process')
+const { join } = require('path')
+
+const { Octokit } = require('@octokit/rest')
+const chalk = require('chalk')
+const putasset = require('putasset')
+
+const platforms = require('./platforms')
+
+const version = execSync('git log -1 --pretty=%B', {
+  encoding: 'utf8',
+})
+
+;(async () => {
+  const [owner, repo] = process.env.GITHUB_REPOSITORY.split('/')
+  const octokit = new Octokit({
+    auth: process.env.GITHUB_TOKEN,
+  })
+  await octokit.repos.createRelease({
+    owner,
+    repo,
+    tag_name: version,
+  })
+  await Promise.all(
+    platforms.map(async (platform) => {
+      const binary = join(__dirname, '..', `bindings-${platform}`, `index.${platform}.node`)
+      const downloadUrl = await putasset(process.env.GITHUB_TOKEN, {
+        owner,
+        repo,
+        tag: version,
+        filename: binary,
+      })
+      console.info(`${chalk.green(binary)} upload success`)
+      console.info(`Download url: ${chalk.blueBright(downloadUrl)}`)
+    }),
+  )
+})().catch((e) => {
+  console.error(e)
+})

+ 17 - 0
scripts/version.js

@@ -0,0 +1,17 @@
+const { execSync } = require('child_process')
+const path = require('path')
+
+const { version } = require('../package.json')
+const platforms = require('./platforms')
+const updatePackageJson = require('./update-package')
+
+for (const name of platforms) {
+  const pkgDir = path.join(__dirname, '..', 'npm', name)
+  updatePackageJson(path.join(pkgDir, 'package.json'), {
+    version,
+  })
+}
+
+execSync('git add .', {
+  stdio: 'inherit',
+})

+ 53 - 0
src/lib.rs

@@ -0,0 +1,53 @@
+#[macro_use]
+extern crate napi;
+#[macro_use]
+extern crate napi_derive;
+
+use std::convert::TryInto;
+
+use napi::{CallContext, Env, JsNumber, JsObject, Module, Result, Task};
+
+#[cfg(all(unix, not(target_env = "musl")))]
+#[global_allocator]
+static ALLOC: jemallocator::Jemalloc = jemallocator::Jemalloc;
+
+register_module!(example, init);
+
+struct AsyncTask(u32);
+
+impl Task for AsyncTask {
+  type Output = u32;
+  type JsValue = JsNumber;
+
+  fn compute(&mut self) -> Result<Self::Output> {
+    use std::thread::sleep;
+    use std::time::Duration;
+    sleep(Duration::from_millis(self.0 as u64));
+    Ok(self.0 * 2)
+  }
+
+  fn resolve(&self, env: &mut Env, output: Self::Output) -> Result<Self::JsValue> {
+    env.create_uint32(output)
+  }
+}
+
+fn init(module: &mut Module) -> Result<()> {
+  module.create_named_method("sync", sync_fn)?;
+
+  module.create_named_method("sleep", sleep)?;
+  Ok(())
+}
+
+#[js_function(1)]
+fn sync_fn(ctx: CallContext) -> Result<JsNumber> {
+  let argument: u32 = ctx.get::<JsNumber>(0)?.try_into()?;
+
+  ctx.env.create_uint32(argument + 100)
+}
+
+#[js_function(1)]
+fn sleep(ctx: CallContext) -> Result<JsObject> {
+  let argument: u32 = ctx.get::<JsNumber>(0)?.try_into()?;
+  let task = AsyncTask(argument);
+  ctx.env.spawn(task)
+}

文件差异内容过多而无法显示
+ 2525 - 0
yarn.lock