從零開始發布自己的NPM包

大家好,我是若川。持續組織了6個月源碼共讀活動,感興趣的可以點此加我微信 ruochuan02?參與,每周大家一起學習200行左右的源碼,共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》?包含20余篇源碼文章。歷史面試系列

在Verdaccio搭建npm私有服務器中,我們介紹了如何搭建一個Npm私有服務器;服務器搭建完成后,我們本文來學習一下如何上傳我們自己的npm包。

前端模塊化作為前端必備的一個技能,已經在前端開發中不可或缺;而模塊化帶來項目的規模不斷變大,項目的依賴越來越多;隨著項目的增多,如果每個模塊都通過手動拷貝的方式無異于飲鴆止渴,我們可以把功能相似的模塊或組件抽取到一個npm包中;然后上傳到私有npm服務器,不斷迭代npm包來更新管理所有項目的依賴。

npm包的基本了解

首先我們來了解一下實現一個npm包需要包含哪些內容。

打包

通常,我們把打包好的一些模塊文件放在一個目錄下,便于統一進行加載;是的,npm包也是需要進行打包的,雖然也能直接寫npm包模塊的代碼(并不推薦),但我們經常會在項目中用到typescript、babel、eslint、代碼壓縮等等功能,因此我們也需要對npm包進行打包后再進行發布。

在深入對比Webpack、Parcel、Rollup打包工具中,我們總結了,rollup相比于webpack更適合打包一些第三方的類庫,因此本文主要通過rollup來進行打包。

npm域級包

隨著npm包越來越多,而且包名也只能是唯一的,如果一個名字被別人占了,那你就不能再使用這個名字;假設我想要開發一個utils包,但是張三已經發布了一個utils包,那我的包名就不能叫utils了;此時我們可以加一些連接符或者其他的字符進行區分,但是這樣就會讓包名不具備可讀性。

在npm的包管理系統中,有一種scoped packages機制,用于將一些npm包以@scope/package的命名形式集中在一個命名空間下面,實現域級的包管理。

域級包不僅不用擔心會和別人的包名重復,同時也能對功能類似的包進行統一的劃分和管理;比如我們用vue腳手架搭建的項目,里面就有@vue/cli-plugin-babel@vue/cli-plugin-eslint等等域級包。

我們在初始化項目時可以使用命令行來添加scope:

npm?init?--scope=username

相同域級范圍內的包會被安裝在相同的文件路徑下,比如node_modules/@username/,可以包含任意數量的作用域包;安裝域級包也需要指明其作用域范圍:

npm?install?@username/package

在代碼中引入時同樣也需要作用域范圍:

require("@username/package")

加載規則

在npm包中的package.json文件,我們經常會看到mainjsnext:mainmodulebrowser等字段,那么這些字段都代表了什么意思呢?其實這跟npm包的工作環境有關系,我們知道,npm包分為以下幾種類型的包:

  • 只能在瀏覽器端使用的

  • 只能在服務器端使用的

  • 瀏覽器/服務器端都可使用

假如我們現在開發一個npm包,既要支持瀏覽器端,也要支持服務器端(比如axios、lodash等),需要在不同的環境下加載npm包的不同入口文件,只通過一個字段已經不能滿足需求。

首先我們來看下main字段,它是nodejs默認文件入口, 支持最廣泛,主要使用在引用某個依賴包的時候需要此屬性的支持;如果不使用main字段的話,我們可能需要這樣來引用依賴:

import('some-module/dist/bundle.js')

所以它的作用是來告訴打包工具,npm包的入口文件是哪個,打包時讓打包工具引入哪個文件;這里的文件一般是commonjs(cjs)模塊化的。

有一些打包工具,例如webpack或rollup,本身就能直接處理import導入的esm模塊,那么我們可以將模塊文件打包成esm模塊,然后指定module字段;由包的使用者來決定如何引用。

jsnext:mainmodule字段的意義是一樣的,都可以指定esm模塊的文件;但是jsnext:main是社區約定的字段,并非官方,而module則是官方約定字段,因此我們經常將兩個字段同時使用。

在Webpack配置全解析中我們介紹到,mainFields就是webpack用來解析模塊的,默認會按照順序解析browser、module、main字段。

有時候我們還想要寫一個同時能夠跑在瀏覽器端和服務器端的npm包(比如axios),但是兩者在運行環境上還是有著細微的區別,比如瀏覽器請求數據用的是XMLHttpRequest,而服務器端則是http或者https;那么我們要怎樣來區分不同的環境呢?

除了我們可以在代碼中對環境參數進行判斷(比如判斷XMLHttpRequest是否為undefined),也可以使用browser字段,在瀏覽器環境來替換main字段。browser的用法有以下兩種,如果browser為單個的字符串,則替換main成為瀏覽器環境的入口文件,一般是umd模塊的:

{"browser":?"./dist/bundle.umd.js"
}

browser還可以是一個對象,來聲明要替換或者忽略的文件;這種形式比較適合替換部分文件,不需要創建新的入口。key是要替換的module或者文件名,右側是替換的新的文件,比如在axios的packages.json中就用到了這種替換:

{"browser":?{"./lib/adapters/http.js":?"./lib/adapters/xhr.js"}
}

打包工具在打包到瀏覽器環境時,會將引入來自./lib/adapters/http.js的文件內容替換成./lib/adapters/xhr.js的內容。

在有一些包中我們還會看到types字段,指向types/index.d.ts文件,這個字段是用來包含了這個npm包的變量和函數的類型信息;比如我們在使用lodash-es包的時候,有一些函數的名稱想不起來了,只記得大概的名字;比如輸入fi就能自動在編譯器中聯想出fill或者findIndex等函數名稱,這就為包的使用者提供了極大的便利,不需要去查看包的內容就能了解其導出的參數名稱,為用戶提供了更加好的IDE支持。

發布哪些文件

在npm包中,我們可以選擇哪些文件發布到服務器中,比如只發布壓縮后的代碼,而過濾源代碼;我們可以通過配置文件來進行指定,可以分為以下幾種情況:

  • 存在.npmignore文件,以.npmignore文件為準,在文件中的內容都會被忽略,不會上傳;即使有.gitignore文件,也不會生效。

  • 不存在.npmignore文件,以.gitignore文件為準,一般是無關內容,例如.vscode等環境配置相關的。

  • 不存在.npmignore也不存在.gitignore,所有文件都會上傳。

  • package.json中存在files字段,可以理解為files為白名單。

ignore相當于黑名單,files字段就是白名單,那么當兩者內容沖突時,以誰為準呢?答案是files為準,它的優先級最高。

我們可以通過npm pack命令進行本地模擬打包測試,在項目根目錄下就會生成一個tgz的壓縮包,這就是將要上傳的文件內容。

項目依賴

在package.json文件中,所有的依賴包都會在dependencies和devDependencies字段中進行配置管理:

  • dependencies:表示生產環境下的依賴管理,--save 簡寫 -S;

  • devDependencies:表示開發環境下的依賴管理,--save-dev 簡寫 -D;

dependencies字段指定了項目上線后運行所依賴的模塊,可以理解為我們的項目在生產環境運行中要用到的東西;比如vue、jquery、axios等,項目上線后還是要繼續使用的依賴。

devDependencies字段指定了項目開發所需要的模塊,開發環境會用到的東西;比如webpack、eslint等等,我們打包的時候會用到,但是項目上線運行時就不需要了,所以放到devDependencies中去就好了。

除了dependencies和devDependencies字段,我們在一些npm包中還會看到peerDependencies字段,沒有寫過npm插件的童鞋可能會對這個字段比較陌生,它和上面兩個依賴有什么區別呢?

假設我們的項目MyProject,有一個依賴PackageA,它的package.json中又指定了對PackageB的依賴,因此我們的項目結構是這樣的:

MyProject
|-?node_modules|-?PackageA|-?node_modules|-?PackageB

那么我們在MyProject中是可以直接引用PackageA的依賴的,但如果我們想直接使用PackageB,那對不起,是不行的;即使PackageB已經被安裝了,但是node只會在MyProject/node_modules目錄下查找PackageB。

為了解決這樣問題,peerDependencies字段就被引入了,通俗的解釋就是:如果你安裝了我,你最好也安裝以下依賴。比如上面如果我們在PackageA的package.json中加入下面代碼:

{"peerDependencies":?{"PackageB":?"1.0.0"}
}

這樣如果你安裝了PackageA,那會自動安裝PackageB,會形成如下的目錄結構:

MyProject
|-?node_modules|-?PackageA|-?PackageB

我們在MyProject項目中就能愉快的使用PackageA和PackageB兩個依賴了。

比如,我們熟悉的element-plus組件庫,它本身不可能單獨運行,必須依賴于vue3環境才能運行;因此在它的package.json中我們看到它對宿主環境的要求:

{"peerDependencies":?{"vue":?"^3.2.0"},
}

這樣我們看到它在組件中引入的vue的依賴,其實都是宿主環境提供的vue3依賴:

import?{?ref,?watch,?nextTick?}?from?'vue'

許可證

license字段使我們可以定義適用于package.json所描述代碼的許可證。同樣,在將項目發布到npm注冊時,這非常重要,因為許可證可能會限制某些開發人員或組織對軟件的使用。擁有清晰的許可證有助于明確定義該軟件可以使用的術語。

借用知乎上Max Law的一張圖來解釋所有的許可證:

f275b4a5c434ef9e18ffe5e5521d87fc.png
許可證

版本號

npm包的版本號也是有規范要求的,通用的就是遵循semver語義化版本規范,版本格式為:major.minor.patch,每個字母代表的含義如下:

  1. 主版本號(major):當你做了不兼容的API修改

  2. 次版本號(minor):當你做了向下兼容的功能性新增

  3. 修訂號(patch):當你做了向下兼容的問題修正

先行版本號是加到修訂號的后面,作為版本號的延伸;當要發行大版本或核心功能時,但不能保證這個版本完全正常,就要先發一個先行版本。

先行版本號的格式是在修訂版本號后面加上一個連接號(-),再加上一連串以點(.)分割的標識符,標識符可以由英文、數字和連接號([0-9A-Za-z-])組成。例如:

1.0.0-alpha
1.0.0-alpha.1
1.0.0-0.3.7

常見的先行版本號有:

  1. alpha:不穩定版本,一般而言,該版本的Bug較多,需要繼續修改,是測試版本

  2. beta:基本穩定,相對于Alpha版已經有了很大的進步,消除了嚴重錯誤

  3. rc:和正式版基本相同,基本上不存在導致錯誤的Bug

  4. release:最終版本

9e23052926c3a6557fb5872f5614b7af.png
版本號

每個npm包的版本號都是唯一的,我們每次更新npm包后,都是需要更新版本號,否則會報錯提醒:

d91cce762e89a7612d9e3d368f07a63b.png
版本號報錯
?

當主版本號升級后,次版本號和修訂號需要重置為0,次版本號進行升級后,修訂版本需要重置為0。

?

但是如果每次都要手動來更新版本號,那可就太麻煩了;那么是否有命令行能來自動更新版本號呢?由于版本號的確定依賴于內容決定的主觀性的動作,因此不能完全做到全自動化更新,誰知道你是改了大版本還是小版本,因此只能通過命令行實現半自動操作;命令的取值和語義化的版本是對應的,會在相應的版本上加1:

df78db25ab195ba4a4885480dad99768.png
命令行更新版本號

在package.json的一些依賴的版本號中,我們還會看到^~或者>=這樣的標識符,或者不帶標識符的,這都代表什么意思呢?

  1. 沒有任何符號:完全百分百匹配,必須使用當前版本號

  2. 對比符號類的:>(大于) ?>=(大于等于) <(小于) <=(小于等于)

  3. 波浪符號~:固定主版本號和次版本號,修訂號可以隨意更改,例如~2.0.0,可以使用 2.0.0、2.0.2 、2.0.9 的版本。

  4. 插入符號^:固定主版本號,次版本號和修訂號可以隨意更改,例如^2.0.0,可以使用 2.0.1、2.2.2 、2.9.9 的版本。

  5. 任意版本*:對版本沒有限制,一般不用

  6. 或符號:||可以用來設置多個版本號限制規則,例如 >= 3.0.0 || <= 1.0.0

npm包開發

通過上面對package.json的介紹,相信各位小伙伴已經對npm包有了一定的了解,現在我們就進入代碼實操階段,開發并上傳一個npm包。

工具類包

相信不少童鞋在業務開發時都會遇到重復的功能,或者開發相同的工具函數,每次遇到時都要去其他項目中拷貝代碼;如果一個項目的代碼邏輯有優化的地方,需要同步到其他項目,則需要再次挨個項目的拷貝代碼,這樣不僅費時費力,而且還重復造輪子。

我們可以整合各個項目的需求,開發一個適合自己項目的工具類的npm包,包的結構如下:

hello-npm
|--?lib/(存放打包后的文件)
|--?src/(源碼)
|--?package.json
|--?rollup.config.base.js(rollup基礎配置)
|--?rollup.config.dev.js(rollup開發配置)
|--?rollup.config.js(rollup正式配置)
|--?README.md
|--?tsconfig.json

首先看下package.json的配置,rollup根據開發環境區分不同的配置:

{"name":?"hello-npm","version":?"1.0.0","description":?"我是npm包的描述","main":?"lib/bundle.cjs.js","jsnext:main":?"lib/bundle.esm.js","module":?"lib/bundle.esm.js","browser":?"lib/bundle.browser.js","types":?"types/index.d.ts","author":?"","scripts":?{"dev":?"npx?rollup?-wc?rollup.config.dev.js","build":?"npx?rollup?-c?rollup.config.js?&&?npm?run?build:types","build:types":?"npx?tsc",},"license":?"ISC"
}

然后配置rollup的base config文件:

import?typescript?from?"@rollup/plugin-typescript";
import?pkg?from?"./package.json";
import?json?from?"rollup-plugin-json";
import?resolve?from?"rollup-plugin-node-resolve";
import?commonjs?from?"@rollup/plugin-commonjs";
import?eslint?from?"@rollup/plugin-eslint";
import?{?babel?}?from?'@rollup/plugin-babel'
const?formatName?=?"hello";
export?default?{input:?"./src/index.ts",output:?[{file:?pkg.main,format:?"cjs",},{file:?pkg.module,format:?"esm",},{file:?pkg.browser,format:?"umd",name:?formatName,},],plugins:?[json(),commonjs({include:?/node_modules/,}),resolve({preferBuiltins:?true,jsnext:?true,main:?true,brower:?true,}),typescript(),eslint(),babel({?exclude:?"node_modules/**"?}),],
};

這里我們將打包成commonjs、esm和umd三種模塊規范的包,然后是生產環境的配置,加入terser和filesize分別進行壓縮和查看打包大小:

import?{?terser?}?from?"rollup-plugin-terser";
import?filesize?from?"rollup-plugin-filesize";import?baseConfig?from?"./rollup.config.base";export?default?{...baseConfig,plugins:?[...baseConfig.plugins,?terser(),?filesize()],
};

然后是開發環境的配置:

import?baseConfig?from?"./rollup.config.base";
import?serve?from?"rollup-plugin-serve";
import?livereload?from?"rollup-plugin-livereload";export?default?{...baseConfig,plugins:?[...baseConfig.plugins,serve({contentBase:?"",port:?8020,}),livereload("src"),],
};

環境配置好后,我們就可以打包了

#?測試環境
npm?run?dev
#?生產環境
npm?run?build

全局包

還有一類npm包比較特殊,是通過npm i -g [pkg]進行全局安裝的,比如常用的vue createstatic-serverpm2等命令,都是通過全局命令安裝的;那么全局npm包如何開發呢?

我們來實現一個全局命令的計算器功能,新建一個項目然后運行:

cd?my-calc
npm?init?-y

在package.json中添加bin屬性,它是一個對象,鍵名是告訴node在全局定義一個全局的命令,值則是執行命令的腳本文件路徑,可以同時定義多個命令,這里我們定義一個calc命令

{"name":?"my-calc","version":?"1.0.0","description":?"","main":?"index.js","scripts":?{"test":?"echo?\"Error:?no?test?specified\"?&&?exit?1"},"bin":?{"calc":?"./src/calc.js",},"license":?"ISC",
}

命令定義好了,我們來實現calc.js中的內容:

#!/usr/bin/env?nodeif?(process.argv.length?<=?2)?{console.log("請輸入運算的數字");return;
}let?total?=?process.argv.slice(2).map((el)?=>?{let?parseEl?=?parseFloat(el);return?!isNaN(parseEl)???parseEl?:?0;}).reduce((total,?num)?=>?{total?+=?num;return?total;},?0);console.log(`運算結果:${total}`);

需要注意的是,文件頭部的#!/usr/bin/env node是必須的,告訴node這是一個可執行的js文件,如果不寫會報錯;然后通過process.argv.slice(2)來獲取執行命令的參數,前兩個參數分別是node的運行路徑和可執行腳本的運行路徑,第三個參數開始才是命令行的參數,因此我們在命令行運行來看結果:

calc?1?2?3?-4

如果我們的腳本比較復雜,想調試一下腳本,那么每次都需要發布到npm服務器,然后全局安裝后才能測試,這樣比較費時費力,那么有沒有什么方法能夠直接運行腳本呢?這里就要用到npm link命令,它的作用是將調試的npm模塊鏈接到對應的運行項目中去,我們也可以通過這個命令把模塊鏈接到全局。

在我們的項目中運行命令:

npm?link

可以看到全局npm目錄下新增了calc文件,calc命令就指向了本地項目下的calc.js文件,然后我們就可以盡情的運行調試;調試完成后,我們又不需要將命令指向本地項目了,這個時候就需要下面的命令進行解綁操作

npm?unlink

解綁后npm會把全局的calc文件刪除,這時候我們就可以去發布npm包然后進行真正的全局安裝了。

vue組件庫

在Vue項目中,我們在很多項目中也會用到公共組件,可以將這些組件提取到組件庫,我們可以仿照element-ui來實現一個我們自己的ui組件庫;首先來構建我們的項目目錄:

|-?lib
|-?src|-?MyButton|-?index.js|-?index.vue|-?index.scss|-?MyInput|-?index.js|-?index.vue|-?index.scss|-?main.js
|-?rollup.config.js

我們構建MyButton和MyInput兩個組件,vue文件和scss不再贅述,我們來看下導出組件的index.js:

import?MyButton?from?"./index.vue";MyButton.install?=?function?(Vue)?{Vue.component(MyButton.name,?MyButton);
};
export?default?MyButton;

組件導出后在main.js中統一組件注冊:

import?MyButton?from?"./MyButton/index.js";
import?MyInput?from?"./MyInput/index";
import?{?version?}?from?"../package.json";import?"./MyButton/index.scss";
import?"./MyInput/index.scss";const?components?=?[MyButton,?MyInput];const?install?=?function?(Vue)?{components.forEach((component)?=>?{Vue.component(component.name,?component);});
};
if?(typeof?window?!==?"undefined"?&&?window.Vue)?{install(window.Vue);
}
export?{?MyButton,?MyInput,?install?};
export?default?{?version,?install?};

然后配置rollup.config.js:

import?resolve?from?"rollup-plugin-node-resolve";
import?vue?from?"rollup-plugin-vue";
import?babel?from?"@rollup/plugin-babel";
import?commonjs?from?"@rollup/plugin-commonjs";
import?scss?from?"rollup-plugin-scss";
import?json?from?"@rollup/plugin-json";const?formatName?=?"MyUI";
const?config?=?{input:?"./src/main.js",output:?[{file:?"./lib/bundle.cjs.js",format:?"cjs",name:?formatName,exports:?"auto",},{file:?"./lib/bundle.js",format:?"iife",name:?formatName,exports:?"auto",},],plugins:?[json(),resolve(),vue({css:?true,compileTemplate:?true,}),babel({exclude:?"**/node_modules/**",}),commonjs(),scss(),],
};
export?default?config;

這里我們打包出commonjs和iife兩個模塊規范,一個可以配合打包工具使用,另一個可以直接在瀏覽器中script引入。我們通過rollup-plugin-vue插件來解析vue文件,需要注意的是5.x版本解析vue2,最新的6.x版本解析vue3,默認安裝6.x版本;如果我們使用的是vue2,則需要切換老版本的插件,還需要安裝以下vue的編譯器:

npm?install?--save-dev?vue-template-compiler

打包成功后我們就能看到lib目錄下的文件了,我們就能像element-ui一樣,愉快的使用自己的ui組件了,在項目中引入我們的UI:

/*?全局引入?main.js?*/
import?MyUI?from?"my-ui";
//?引入樣式
import?"my-ui/lib/bundle.cjs.css";Vue.use(MyUI);/*?在組件中按需引入?*/
import?{?MyButton?}?from?"my-ui";
export?default?{components:?{MyButton}
}

如果想要在本地進行調試,也可以使用link命令創建鏈接,首先在my-ui目錄下運行npm link將組件掛載到全局,然后在vue項目中運行下面命令來引入全局的my-ui:

npm?link?my-ui

我們會看到下面的輸出表示vue項目中my-ui模塊已經鏈接到my-ui項目了:

D:\project\vue-demo\node_modules\my-ui?
->?
C:\Users\XXXX\AppData\Roaming\npm\node_modules\my-ui
->?
D:\project\my-ui

npm包發布

我們的npm包完成后就可以準備發布了,首先我們需要準備一個賬號,可以使用--registry來指定npm服務器,或者直接使用nrm來管理:

npm?adduser
npm?adduser?--registry=http://example.com

然后進行登錄,輸入你注冊的賬號密碼郵箱:

npm?login

還可以用下面命令退出當前賬號

npm?logout

如果不知道當前登錄的賬號可以用who命令查看身份:

npm?who?am?i

登錄成功就可以將我們的包推送到服務器上去了,執行下面命令,會看到一堆的npm notice:

npm?publish

如果某版本的包有問題,我們還可以將其撤回

npm?unpublish?[pkg]@[version]


c34c2e07805d6f80a6955226e9bfee9e.gif

·················?若川簡介?·················

你好,我是若川,畢業于江西高校。現在是一名前端開發“工程師”。寫有《學習源碼整體架構系列》20余篇,在知乎、掘金收獲超百萬閱讀。
從2014年起,每年都會寫一篇年度總結,已經寫了7篇,點擊查看年度總結。
同時,最近組織了源碼共讀活動,幫助3000+前端人學會看源碼。公眾號愿景:幫助5年內前端人走向前列。

cdc5d2ca632bb2b178f902be58999fc4.png

識別方二維碼加我微信、拉你進源碼共讀

今日話題

略。分享、收藏、點贊、在看我的文章就是對我最大的支持~

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/274908.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/274908.shtml
英文地址,請注明出處:http://en.pswp.cn/news/274908.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

flash不能訪問本地文件

flash出現"不能訪問本地資源";解決方案 linux下&#xff0c;如果沒有文件夾自行創建 在/home/{user}/.macromedia/Flash_Player/#Security/FlashPlayerTrust下面&#xff0c;隨便建個文本文件&#xff0c;比如1.txt 然后寫入路徑&#xff0c;最省事的辦法直接來個/ 兇…

Jest + React Testing Library 單測總結

大家好&#xff0c;我是若川。持續組織了6個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan02 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列1、背…

不怕神一樣的對手就怕豬一樣的隊友

“不怕神一樣的對手就怕豬一樣的隊友”這句話現在廣為流傳&#xff0c;實際上說的就是團隊重要性&#xff0c;一個好的團隊是可以克服很多你想象不大的困難&#xff0c; 做出你覺得不可能成績。 但是很多時候我們面臨的不是神一樣的對手&#xff0c;而是豬一樣的隊友&#xff0…

著迷英語900句_字體令人著迷

著迷英語900句I’m crazy about fonts. My favorite part of any text editing software is the drop down menu for picking fonts. When I look at any text, I try to identify the font. Roboto is my favorite font.我為字體瘋狂。 在任何文本編輯軟件中&#xff0c;我最喜…

hdu 2188悼念512汶川大地震遇難同胞——選拔志愿者(博弈)

簡單博弈就那樣&#xff0c;懂SG函數就成&#xff0c;最近做的博弈都千篇一律。。。 #include<cstdio> #include<cstring> #define N 11110 int sg[N],s[N],m,n; bool h[N]; void ssgg() {int i,j;sg[0]0;for(i1;i<N;i){ memset(h,0,sizeof(h));for(j1;j<n;j…

推薦一個大佬,文章適合偷偷讀!

大家好&#xff0c;我是若川。周末愉快。也許你看到這篇文章是周一的上午~我不得不推薦一位大佬給你&#xff01;這位大佬的文章很硬&#xff0c;卻一直在「抱怨沒有粉絲&#xff0c;沒人愿意分享」我去讀了讀&#xff0c;尼瑪這個「誰TM敢分享啊」&#xff0c;文章太「違規」了…

PERFORMANCE-MONITORING(轉)

Performance-Monitoring 是Intel提供的可以監測統計CPU內部所產生事件的一組方法。在Intel的手冊上介紹了兩類CPU事件監測方法&#xff1a;architectural performance monitoring 和 non-architectural performance monitoring。Architectural performance monitoring與平臺&am…

ux設計_為企業UX設計更好的數據表

ux設計重點 (Top highlight)If you have worked on enterprise products, you must have noticed the use of lots of data tables. Therefore, I am writing this article to collect the most common use cases and discuss how elegantly we can handle them.如果您使用過企…

hdu1728--------坑爹啊

尼瑪&#xff0c;就因為沒發現‘yes’寫成‘yrs’。整整讓哥找了一個小時的bug。有沒有..........此刻&#xff0c;內流滿面&#xff01; 分析&#xff1a; 開始以為是單純的BFS,結果WA無數次&#xff01;&#xff01; 后來分析后發現是要找到不超過轉向次數的轉向路徑, 最重要…

狼叔直播 Reaction《學習指北:Node.js 2022 全解析》

大家好&#xff0c;我是若川。持續組織了6個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan02 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列本文是…

figma下載_Figma中的高級圖像處理

figma下載Figma is not exactly suited for image manipulation, and that’s completely fine. While it does provide an ample amount of tools that let you apply some basic changes to your raster images, for anything more complex you need to look someplace else.…

ToString格式化

在很多對象顯示為字符串的時候都會使用到ToString中的格式化&#xff0c;由于以前沒怎么注意到這個問題&#xff0c;想總結一下各個基礎結構對象的格式化&#xff0c;以便后備之用&#xff01;&#xff01;&#xff01;Int.ToString(format): 格式字符串采用以下形式&#xff1…

xml學習4-dtd

1、DTD元素的定義 <?xml version"1.0" encoding"gb2312"?> <!--*表示0或者多個 表示至少要有一個 ?表示0個或者一個 內容模型 |表示只能包含分隔開中的一個 ,表示序列 下面是DTD元素的聲明 #PCDATA 表示字符數據 EMPTY表示 空元素…

指針和指針的指針_網絡上的iPad指針

指針和指針的指針a week ago I saw a new IPad Pointer presentation and was very excited about what they did. It was very interesting to see how they design different pointer modes and attention to details. Here is the presentation:一周前&#xff0c;我看到了一…

Vue 是如何用 Rollup 打包的?

大家好&#xff0c;我是若川。持續組織了6個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列Rollu…

leetcode 207課程表

class Solution { public:bool canFinish(int numCourses, vector<vector<int>>& prerequisites) {//驗證是否為DAG&#xff0c;每次驗證指向的是否已經存在于當前圖中//建圖vector<int> indegree(numCourses,0);//入度vector<vector<int>> …

2012-04-12

一.JS 中的return Return false&#xff1a;相當于一個終止符,用來阻止提交表單或繼續執行下面的代碼&#xff0c;只在當前函數有效&#xff0c;不會影響其他外部函數的執行 Eg: function a(){if(true) return false;} Function test{a();b();c();} //a方法中的return false 不…

sketch怎么傳到ps_2020年從Sketch移植到Figma的詳細指南

sketch怎么傳到psAs we’re locked up in our homes due to COVID-19 pandemic, many of us are working remotely and Figma is a go-to tool for designers for the same.由于COVID-19流行病使我們被關在家里&#xff0c;我們中的許多人都在遠程工作&#xff0c;而Figma是設計…

還沒搭建過Vue3.x項目?幾行代碼搞定~

大家好&#xff0c;我是若川。持續組織了6個月源碼共讀活動&#xff0c;感興趣的可以點此加我微信 ruochuan12 參與&#xff0c;每周大家一起學習200行左右的源碼&#xff0c;共同進步。同時極力推薦訂閱我寫的《學習源碼整體架構系列》 包含20余篇源碼文章。歷史面試系列相信現…

mysql 常用命令 匯總

參考閱讀 摘要 權限 允許公網訪問列操作 修改列名mysql 修改列屬性其他 登錄設置自動補全與utf-8編碼其他一次添加多條記錄修改表名字允許公網訪問 1,修改表,登錄mysql數據庫,切換到mysql數據庫,使用sql語句查看"select host,user from user ;" mysql -u root -pvmwa…