Chai I Young
    • Create new note
    • Create a note from template
      • Sharing URL Link copied
      • /edit
      • View mode
        • Edit mode
        • View mode
        • Book mode
        • Slide mode
        Edit mode View mode Book mode Slide mode
      • Customize slides
      • Note Permission
      • Read
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Write
        • Only me
        • Signed-in users
        • Everyone
        Only me Signed-in users Everyone
      • Engagement control Commenting, Suggest edit, Emoji Reply
    • Invite by email
      Invitee

      This note has no invitees

    • Publish Note

      Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

      Your note will be visible on your profile and discoverable by anyone.
      Your note is now live.
      This note is visible on your profile and discoverable online.
      Everyone on the web can find and read all notes of this public team.
      See published notes
      Unpublish note
      Please check the box to agree to the Community Guidelines.
      View profile
    • Commenting
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
      • Everyone
    • Suggest edit
      Permission
      Disabled Forbidden Owners Signed-in users Everyone
    • Enable
    • Permission
      • Forbidden
      • Owners
      • Signed-in users
    • Emoji Reply
    • Enable
    • Versions and GitHub Sync
    • Note settings
    • Note Insights
    • Engagement control
    • Transfer ownership
    • Delete this note
    • Save as template
    • Insert from template
    • Import from
      • Dropbox
      • Google Drive
      • Gist
      • Clipboard
    • Export to
      • Dropbox
      • Google Drive
      • Gist
    • Download
      • Markdown
      • HTML
      • Raw HTML
Menu Note settings Versions and GitHub Sync Note Insights Sharing URL Create Help
Create Create new note Create a note from template
Menu
Options
Engagement control Transfer ownership Delete this note
Import from
Dropbox Google Drive Gist Clipboard
Export to
Dropbox Google Drive Gist
Download
Markdown HTML Raw HTML
Back
Sharing URL Link copied
/edit
View mode
  • Edit mode
  • View mode
  • Book mode
  • Slide mode
Edit mode View mode Book mode Slide mode
Customize slides
Note Permission
Read
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Write
Only me
  • Only me
  • Signed-in users
  • Everyone
Only me Signed-in users Everyone
Engagement control Commenting, Suggest edit, Emoji Reply
  • Invite by email
    Invitee

    This note has no invitees

  • Publish Note

    Share your work with the world Congratulations! 🎉 Your note is out in the world Publish Note

    Your note will be visible on your profile and discoverable by anyone.
    Your note is now live.
    This note is visible on your profile and discoverable online.
    Everyone on the web can find and read all notes of this public team.
    See published notes
    Unpublish note
    Please check the box to agree to the Community Guidelines.
    View profile
    Engagement control
    Commenting
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    • Everyone
    Suggest edit
    Permission
    Disabled Forbidden Owners Signed-in users Everyone
    Enable
    Permission
    • Forbidden
    • Owners
    • Signed-in users
    Emoji Reply
    Enable
    Import from Dropbox Google Drive Gist Clipboard
       owned this note    owned this note      
    Published Linked with GitHub
    Subscribed
    • Any changes
      Be notified of any changes
    • Mention me
      Be notified of mention me
    • Unsubscribe
    Subscribe
    # Nest.js ## [套件管理](https://hackmd.io/@yygg/SJkw6JxNh) ## Nest.js最基礎的概念--模塊化+依賴注入 imports :導入其他模塊中導出的Provider,實現共享。 providers :模塊中所有共享的class,共享使用。 controllers:路由控制器。 exports:導出其他模塊需要共享的Providers。\ nest.js的基本觀念: https://juejin.cn/post/6925605351475806216 跟以下搭配看: https://www.cnblogs.com/songyao666/p/17583017.html ## 專案初始化 直接在terminal個根目錄操作,會建立一個[app name]的資料夾在根目錄下: `$ nest new [app name]` <p style="color:rgb(192,192,192)">原本有遇到一些狀況:建立一個一般的node專案後,在terminal安裝nest,再nest new,然後會報錯,說找不到"node:fs" module,於是我找到要引入fs模組的位置(因為我不知道在全域要怎麼改到node的module,還是是我的npm的版本太舊?),將node:fs和node:path都去掉"node:",nest new時就可以成功,但是他是建立一個專案資料夾在原本node的資料夾下,我又把他拉出來,git也刪掉(nest cli會自動幫我建立git),重新上傳git才成功的。</p> <li>Nest.js hot reload:</li> https://docs.nestjs.com/recipes/hot-reload 同時修改script中的`"start:dev": "nest start --watch"` <li>yarn版本:</li> 如遇到以下錯誤,記得先檢查script中的: ![](https://i.imgur.com/lfoFsMK.png) 嘗試過:更新node版本後,將以下安裝在dev但還是不行(因原本是安裝在dependencies,改安裝在devDependencies)。 `yarn add webpack-node-externals start-server-webpack-plugin --D` 【教學文】https://ithelp.ithome.com.tw/articles/10244359 如遇以下錯誤,要用nvm use 16轉換node版本 ![](https://i.imgur.com/MbYYje7.png) ## 專案架構 建議的的nest基礎架構。 https://juejin.cn/post/6844904192687996936 ``` nodejs ├── package.json ├── README.md ├── src │ │ └── constants(全局常量定义) │ │ ├──common.constants.ts │ │ └── utils(常用工具类) │ │ ├──http.util.ts │ │ └──file.util.ts │ ├── app.module.ts(模块配置文件) │ ├── common (通用模块,包含自定义装饰器、过滤器、守卫、拦截器、中间件) │ │ ├── decorators (项目通用装饰器) │ │ │ └── roles.decorator.ts │ │ ├── filters (过滤器) │ │ │ └── http-exception.filter.ts │ │ ├── guards (守卫) │ │ │ └── roles.guard.ts │ │ ├── interceptors (拦截器) │ │ │ ├── exception.interceptor.ts │ │ │ ├── logging.interceptor.ts │ │ ├── middleware (中间件) │ │ │ └── logger.middleware.ts │ │ └── pipes (管道,主要用于数据验证和类型转换) │ │ ├── parse-int.pipe.ts │ │ └── validation.pipe.ts │ ├── config (配置文件信息) │ │ ├── database.ts │ │ ├── redis.ts │ ├── jobs (高并发场景下队列处理) │ ├── main.ts (入口文件) │ ├── modules (业务代码,按目录区分模块) │ │ ├── hello │ │ │ ├── hello.controller.ts │ │ │ ├── hello.module.ts │ │ │ └── hello.service.ts │ │ └── users │ │ │ ├── dto (数据传输对象定义) │ │ │ │ └── users.create.dto.ts │ │ │ │ └── users.update.dto.ts │ │ ├── users.controller.ts (控制层) │ │ ├── users.entity.ts (映射数据库模型对象) │ │ ├── users.module.ts (模块定义) │ │ └── users.service.ts (service层) │ ├── tasks (定时任务) │ │ ├── tasks.module.ts │ │ └── tasks.service.ts │ └── templates (页面模板) ├── test (单元测试) │ ├── app.e2e-spec.ts ├── tsconfig.json ``` 設定架構和module module設定方法可用cli參考: https://ithelp.ithome.com.tw/articles/10239654 自動匯入module用法: https://ithelp.ithome.com.tw/articles/10268254 ### 【Module】(Nestjs基本核心) <span style="color:rgb(50,192,50)">Q:自定義provider的用意?</span> https://ithelp.ithome.com.tw/articles/10269186 https://ithelp.ithome.com.tw/articles/10269595 A:基本上在實作 Dynamic Module 就有很高的機會會使用到,或是使用第三方套件要將該套件建立的實例納入 NestJS 的依賴注入機制。還有一種使用的時機是撰寫測試,可以運用自訂 Provider 來 Mock。(這邊不太確定實際作法) A:如果一個第三方套件不能用injectable來注入,就可以自定義provider來把套件包裝成可以注入的provider <span style="color:rgb(50,192,50)">Q:若有兩個service是一樣的功能,不同的module可以注入同一個service嗎?</span> A: 若A module和B Module要共用A service,B module就直接引入A module就可以使用A service了 ☆★快速生成module controller service entity也先幫你設置好資料夾架構了(會直接建立在src下,所以後面的path不用再加src) `nest g resource modules/user` ●Component vs Module [功能]:Component 負責提供特定的服務或功能,而 Module 則負責將多個 Component 組合在一起形成一個功能單元。 [範圍]:Component 的作用範圍僅限於自己所在的 Module 中,而 Module 則可以跨多個 Module 嵌套和共用。 [注冊方式]:Component 通常是通過裝飾器(如 @Component、@Controller、@Service、@Injectable)來標記的,並且需要註冊到 Module 中。而 Module 則是通過裝飾器(如 @Module)來標記並註冊到應用程序中。 [依賴關係]:Component 可以依賴其他的 Component 或 Provider,而 Module 可以依賴其他的 Module。 ### 【依賴注入】(控制反轉IOC的一種技術) nest.js中的依賴注入就是讓class不用再經過new產生實例,而是透過註冊(依賴注入的方式)由nest的容器平台統一管理。 https://juejin.cn/post/7176298965401337917 IOC的好處: https://hackmd.io/@kenny88881234/rJwqJbT4S ●要注意在nest中,要使用可以Injectable的類,constructor內建立要在此module內使用的服務,要確保他是可以被注入的 以下就是不能被注入的案例: ![](https://hackmd.io/_uploads/BkbcT4DV3.png) Redis檔案如下: ![](https://hackmd.io/_uploads/B1mA64wNn.png) 因此程式碼需改為: ![](https://hackmd.io/_uploads/BJRg1HwE2.png) 或者也可以寫static方法,將redis寫為LoggerService的方法,此class內要使用的話,就可直接寫LoggerService.redis: ![](https://hackmd.io/_uploads/rk4dmSDNh.png) static的用法是,通常我們需要使用某個class內的用法時,會需要將此class new出來成實例,才可以使用該class內的方法,但是static的用法是就算不new出該class,static的方法也是存在的,且這個class new出來的實例會共用static ### [Provider] 當 Module 建立起來的同時,會把 providers 裡面的項目實例化 以下是縮寫: ``` providers: [AppService], ``` 展開會是: ``` providers: [ { provide: AppService, useClass: AppService } ], ``` Provider有哪些類型: ``` export type Provider<T = any> = | Type<any> // 類型 | ClassProvider<T> // 類 | ValueProvider<T> // 值 | FactoryProvider<T> // 工廠 | ExistingProvider<T>; // 别名 ``` Type 類型 - ClassProvider 類類型的Provider,有三個字段组成: - provide:被注入對象參數,可以是字符串,symbol,類型,抽象類和Function - useClass:類型名稱 - scope:作用域(参考Provider作用域),可選參數,默認scope.DEFAULT,即Application ValueProvider 值類型Provider,有兩個字段组成: - provide:被注入對象參數,可以是字符串,symbol,類型,抽象類和Function - userValue:值的實例 FactoryProvider 工廠類Provider,有四個字段: - provide:被注入對象參數,可以是字符串,symbol,類型,抽象類和Function - useFactory:工廠的參數 - inject:被注入的工廠中上依賴項(可選) - scope:作用域,(可選) ExistingProvider 已经存在的(别名)類Provider,兩個字段: - provide:被注入對象參數,可以是字符串,symbol,類型,抽象類和Function - useExisting:别名 Q:寫在constructor前面的方法跟寫在裡面的差別就只是contructor裡面的是要注入的嗎? ### [Static] https://medium.com/codxfrankenstein/static-in-c-644bca5fd741 ### 【Pipe 參數驗證】 透過DTO寫 https://blog.51cto.com/u_15506823/5113662 要自定義驗證,需安裝class-validator和class-transformer,就可以在DTO中用裝飾器處理並自定義驗證的格式。 若傳到後端的資料為陣列,不能使用 ValidationPipe,要使用 ParseArrayPipe。 https://ithelp.ithome.com.tw/articles/10271720 ◆實作上,我們會希望驗證格式的請求都可以經過pipe,因此通常ValidationPipe會使用在全域,以下全域Pipe放在main.ts,另有一些官方提供的pipe就可能不會放全域,會各自放controller `app.useGlobalPipes(new ValidationPipe())` ![](https://i.imgur.com/wL11gFp.png) ### 【Guard】11 Authorization是Guard經常應用的的實際用法。 在使用websocket 和微服務時,useGlobalGuards()在默認情況下不會設置保護。 若要分角色權限,要在路由加入@setMetadata(),以驗證同一個controller裡的路由,是否可以限制不同的權限只能通過哪些路由。 https://docs.nestjs.com/guards <span style="color:rgb(50,192,50)">Q:直接將express中驗證的middleware passport拉出成為guard的立意?</span> A: 寫法上無法在router直接明確指定要進入哪一個router 官方解釋 <span style="font-size:6pt">But middleware, by its nature, is dumb. It doesn't know which handler will be executed after calling the next() function. On the other hand, Guards have access to the ExecutionContext instance, and thus know exactly what's going to be executed next. They're designed, much like exception filters, pipes, and interceptors, to let you interpose processing logic at exactly the right point in the request/response cycle, and to do so declaratively. This helps keep your code DRY and declarative.</span> https://docs.nestjs.com/guards ### 【Passport】 參考: https://ithelp.ithome.com.tw/articles/10193541 官方: https://docs.nestjs.com/recipes/passport *因AuthModule會使用到UserRepository,因此imports要記得引入typeORM ! *假設全部的路由都要JWT驗證時 *guard 用passport會將guard的回傳值放在req的user裡面,因此在controller裡可以直接用@Req()取到。 https://stackoverflow.com/questions/54979729/howto-get-req-user-in-services-in-nest-js *若沒有使用passport就要自己將user資料放在req.user裡面 https://ithelp.ithome.com.tw/articles/10274416 *要使用RolesGuard驗證權限,可參照: https://stackoverflow.com/questions/71917408/how-to-check-for-roles-in-nestjs-guard ### 【Context(上下文)】 <div style="font-size:6pt">在 Nest.js 中的 context(上下文)是指當 Nest.js 應用程序處理請求時,包含所有有關該請求的信息和數據的對象。這些訊息包括 HTTP 請求的標頭、請求主體、使用者身份驗證數據等等。context 對象被傳遞到應用程式的各個部分,例如中間件、管道、守衛、攔截器和控制器,以便這些部分能夠訪問和處理這些數據。 context 對象還可以包含自定義數據,例如在中間件中設置的數據、從請求中提取的數據等等。這些自定義數據可以在應用程序的各個部分中使用,以便更靈活地處理請求。 總之,context 是一個在 Nest.js 中非常重要的概念,它提供了一個統一的方式來管理請求相關的數據和訊息,並使得應用程序的不同部分可以輕鬆地共享和訪問這些數據。 在 Nest.js 中,context 對象是一個包含請求相關訊息的對象,它在整個應用程序中都是可用的。當一個請求到達應用程式時,Nest.js 會創建一個 context 對象,並將其傳遞到應用程序的各個部分,例如中間件、管道、守衛、攔截器和控制器中。 context 對象包含以下數據: <li>HTTP 請求的標頭、請求主體和 URL 等信息。</li> <li>請求的方法(GET、POST、PUT、DELETE 等)和路由訊息。</li> <li>使用者身份驗證訊息和其他與安全相關的數據。</li> <li>一個可實現自定義數據傳遞的機制,讓您可以在應用程序的不同部分中共享數據。</li> </br> 這些數據可以在應用程序的不同部分中使用,例如: <li>在中間件中使用 context 對象來檢查請求中是否包含特定的標頭或其他信息。</li> <li>在管道中使用 context 對象來驗證請求主體中的數據是否符合要求。</li> <li>在守衛中使用 context 對象來檢查使用者是否有權限訪問某些資源。</li> <li>在攔截器中使用 context 對象來記錄請求的相關信息。 <li>在控制器中使用 context 對象來訪問請求中的數據並返回相應的響應。</li> 總之,context 對象是 Nest.js 應用程序中非常重要的一個概念,它提供了一個統一的方式來管理請求相關的數據和信息,並使得應用程序的不同部分可以輕鬆地共享和訪問這些數據。</div> ### 【Middleware】 ●使用方式: 在根module中實作NestModule與 configure(consumer: MiddlewareConsumer) 方法,並透過 apply 來套用 Middleware,再透過 forRoutes 設置要採用此 Middleware 的路由。 https://ithelp.ithome.com.tw/articles/10272385 (官方文件也有教學:https://docs.nestjs.com/middleware) ### 【Interceptor】 用於處理進入controller之前的請求,可修改請求header、記錄日誌、處理異常(未經授權的請求、發生錯誤的請求..等),Interceptor就是使用靈活度非常大,要做什麼額外處理都可以,要說他也可以涵蓋guard或pipe的功能沒錯,但因為guard就是專門處理驗證身份pipe就是專門處理驗證格式的,因此還是會交由專門的來處理。 好處是可以隔離邏輯,易於維護,詳細可用於以下場景: <li> 認證和授權:可以通過 Interceptor 對請求進行身份驗證和授權,以確保請求的安全性。</li> <li>日誌記錄:可以使用 Interceptor 記錄請求和響應的日誌,以便進行故障排除和性能分析。</li> <li>數據轉換:可以使用 Interceptor 對請求和響應的數據進行轉換和格式化,以適應不同的客戶端和服務端要求。</li> <li>緩存處理:可以使用 Interceptor 對請求和響應進行緩存處理,以提高應用程序的性能和響應速度。</li> <li>錯誤處理:可以使用 Interceptor 對異常進行處理和轉換,以提供更友好的錯誤提示和處理方式。</li> </br> Q:Interceptor有許多功能,但不確定實際可以用在哪裡,因為他可以認證的功能感覺跟guard有重疊,處理錯誤的功能也跟exception filter重疊,是否比較建議用來處理logger日誌? A:例如:Axios 把payload產生一個簽名 資料驗證 log紀錄,都可以是實際應用場景。 ### 【Exception】 Nest 內建的 Exception filter 會去偵測拋出的錯誤是什麼類型的,它只能夠接受 Nest 內建的 HttpException 與繼承該類別的 Exception,若不屬於這類型的錯誤就會直接拋出 Internal server error https://docs.nestjs.com/exception-filters 觀察別人專案exception會寫在service內: https://github.com/fantasticit/wipi/blob/main/packages/server/src/modules/article/article.service.ts ### 【Database】 簡易使用SQLite: ●教學文 https://arctype.com/blog/sqlite-nestjs-tutorial/ ●安裝db和orm `yarn add @nestjs/typeorm typeorm sqlite3` * -D 的意思是安裝在devDependencies,所以正常是不會安裝在dev裡(dev代表開發環境)。 <blockquote style="font-size:8pt">在類 Unix 系統中通常命令參數可以使用 - 或 -- 開頭的單字來傳遞: </br></br> - 只能帶單一字符的參數名 e.g: -D, -v, -y 並且可以一次攜帶多個 e.g -Dvy = -D -v -y</br></br> -- 一次只能攜帶一個參數,但是名稱可以是多個字元組成 e.g --ignore-platform, --force</blockquote> </br> ●使用SQLite typeORM 連接 https://www.makeuseof.com/nestjs-typeorm-sql-databases/ https://tea.ch/article/add-typeorm-to-nestjs-project 在app.module裡TypeOrmModule.forRoot()內的database設定,ORM會自動產生以下檔案在根目錄,去連線資料庫。 `database: "database.db"` ●entity和DTO的理解(是否類似express中model和migration的概念) https://blog.errorbaker.tw/posts/minw/nest-js-intro/ ### 【Swagger API doc】 ●全域引入swagger https://docs.nestjs.com/openapi/introduction#document-options ●controller內可加入decorator @ApiBearerAuth @ApiOperation @ApiResponse ->定義response要回應什麼 @ApiTags ●dto內加入decorator @ApiProperty ●api decorator https://www.makeuseof.com/nestjs-apis-swagger-documentation/ ### 【Adapter】 nest.js基於express https://juejin.cn/post/7070377945553977357 ### 【Nest 的Lifecycle】 Module 初始化階段 (onModuleInit) Nest App 啟動階段 (onApplicationBootstrap) Module 銷毀階段 (onModuleDestroy) Nest App 關閉前 (beforeApplicationShutdown) Nest App 關閉階段 (onApplicationShutdown) 官網圖說,簡單來說就是nest在建立module的時候,都會將module init,在init之前,假設appModule有引入todoModule和userModule,那他會先將依賴項的todoModule和userModule先處理完,再處理appModule,也就是會先處理userModule和todoModule的init最後再處理appModule: https://docs.nestjs.com/fundamentals/lifecycle-events https://ithelp.ithome.com.tw/articles/10276753 ### 【測試】 官方用法 https://docs.nestjs.com/fundamentals/testing ### 【Socket】 https://www.itying.com/nestjs/guide-socket.html ### 【疑問】 ### 【其他狀況】 ●nest-cli突然不能用,先確認是否安裝在全域: `npm list -g --depth 0` 若沒看到@nestjs/cli ,全域再安裝一次 `npm install -g @nestjs/cli` ![](https://i.imgur.com/oqXO2xY.png) ●這個博主提到不安裝@nest/XXX 什麼之類的話,開發是不會有什麼問題,但是他不會給你代碼提示(00:26) https://www.bilibili.com/video/BV1sJ411n7PE/?spm_id_from=333.337.search-card.all.click&vd_source=107ba761a291ed2746522372f562d92e ### 【未整理】 -可看nest.js請求週期 https://www.seozen.top/nestjs-request-lifecycle-middlerware-interceptors-pipes-guards.html

    Import from clipboard

    Paste your markdown or webpage here...

    Advanced permission required

    Your current role can only read. Ask the system administrator to acquire write and comment permission.

    This team is disabled

    Sorry, this team is disabled. You can't edit this note.

    This note is locked

    Sorry, only owner can edit this note.

    Reach the limit

    Sorry, you've reached the max length this note can be.
    Please reduce the content or divide it to more notes, thank you!

    Import from Gist

    Import from Snippet

    or

    Export to Snippet

    Are you sure?

    Do you really want to delete this note?
    All users will lose their connection.

    Create a note from template

    Create a note from template

    Oops...
    This template has been removed or transferred.
    Upgrade
    All
    • All
    • Team
    No template.

    Create a template

    Upgrade

    Delete template

    Do you really want to delete this template?
    Turn this template into a regular note and keep its content, versions, and comments.

    This page need refresh

    You have an incompatible client version.
    Refresh to update.
    New version available!
    See releases notes here
    Refresh to enjoy new features.
    Your user state has changed.
    Refresh to load new user state.

    Sign in

    Forgot password

    or

    By clicking below, you agree to our terms of service.

    Sign in via Facebook Sign in via Twitter Sign in via GitHub Sign in via Dropbox Sign in with Wallet
    Wallet ( )
    Connect another wallet

    New to HackMD? Sign up

    Help

    • English
    • 中文
    • Français
    • Deutsch
    • 日本語
    • Español
    • Català
    • Ελληνικά
    • Português
    • italiano
    • Türkçe
    • Русский
    • Nederlands
    • hrvatski jezik
    • język polski
    • Українська
    • हिन्दी
    • svenska
    • Esperanto
    • dansk

    Documents

    Help & Tutorial

    How to use Book mode

    Slide Example

    API Docs

    Edit in VSCode

    Install browser extension

    Contacts

    Feedback

    Discord

    Send us email

    Resources

    Releases

    Pricing

    Blog

    Policy

    Terms

    Privacy

    Cheatsheet

    Syntax Example Reference
    # Header Header 基本排版
    - Unordered List
    • Unordered List
    1. Ordered List
    1. Ordered List
    - [ ] Todo List
    • Todo List
    > Blockquote
    Blockquote
    **Bold font** Bold font
    *Italics font* Italics font
    ~~Strikethrough~~ Strikethrough
    19^th^ 19th
    H~2~O H2O
    ++Inserted text++ Inserted text
    ==Marked text== Marked text
    [link text](https:// "title") Link
    ![image alt](https:// "title") Image
    `Code` Code 在筆記中貼入程式碼
    ```javascript
    var i = 0;
    ```
    var i = 0;
    :smile: :smile: Emoji list
    {%youtube youtube_id %} Externals
    $L^aT_eX$ LaTeX
    :::info
    This is a alert area.
    :::

    This is a alert area.

    Versions and GitHub Sync
    Get Full History Access

    • Edit version name
    • Delete

    revision author avatar     named on  

    More Less

    Note content is identical to the latest version.
    Compare
      Choose a version
      No search result
      Version not found
    Sign in to link this note to GitHub
    Learn more
    This note is not linked with GitHub
     

    Feedback

    Submission failed, please try again

    Thanks for your support.

    On a scale of 0-10, how likely is it that you would recommend HackMD to your friends, family or business associates?

    Please give us some advice and help us improve HackMD.

     

    Thanks for your feedback

    Remove version name

    Do you want to remove this version name and description?

    Transfer ownership

    Transfer to
      Warning: is a public team. If you transfer note to this team, everyone on the web can find and read this note.

        Link with GitHub

        Please authorize HackMD on GitHub
        • Please sign in to GitHub and install the HackMD app on your GitHub repo.
        • HackMD links with GitHub through a GitHub App. You can choose which repo to install our App.
        Learn more  Sign in to GitHub

        Push the note to GitHub Push to GitHub Pull a file from GitHub

          Authorize again
         

        Choose which file to push to

        Select repo
        Refresh Authorize more repos
        Select branch
        Select file
        Select branch
        Choose version(s) to push
        • Save a new version and push
        • Choose from existing versions
        Include title and tags
        Available push count

        Pull from GitHub

         
        File from GitHub
        File from HackMD

        GitHub Link Settings

        File linked

        Linked by
        File path
        Last synced branch
        Available push count

        Danger Zone

        Unlink
        You will no longer receive notification when GitHub file changes after unlink.

        Syncing

        Push failed

        Push successfully