<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          帶你了解一些package.json的騷操作

          共 12473字,需瀏覽 25分鐘

           ·

          2020-07-28 17:23

          前言 ?

          在每個(gè)項(xiàng)目的根目錄下面,一般都會有一個(gè) package.json 文件,其定義了運(yùn)行項(xiàng)目所需要的各種依賴和項(xiàng)目的配置信息(如名稱、版本、許可證等元數(shù)據(jù))。

          大多數(shù)人對 package.json 文件的了解,僅停留在:

            • 項(xiàng)目名稱、項(xiàng)目構(gòu)建版本、許可證的定義;
            • 依賴定義(包括 dependencies 字段,devDependencies 字段);
            • 使用scripts字段指定運(yùn)行腳本命令的 npm 命令行縮寫。

          其實(shí),package.json 的作用遠(yuǎn)不止于此,我們可以通過新增配置項(xiàng)實(shí)現(xiàn)更強(qiáng)大的功能,下面將帶你重新認(rèn)識  package.json

          由簡入繁,豐富項(xiàng)目的 package.json

          簡單版的 package.json

          當(dāng)我們新建一個(gè)名稱為 my-test 的項(xiàng)目時(shí),使用 yarn init -y 或 npm init -y 命令后,在項(xiàng)目目錄下會新增一個(gè) package.json文件,內(nèi)容如下:
          {
          "name": "my-test", # 項(xiàng)目名稱
          "version": "1.0.0", # 項(xiàng)目版本(格式:大版本.次要版本.小版本)
          "description": "", # 項(xiàng)目描述
          "main": "index.js", # 入口文件
          "scripts": { # 指定運(yùn)行腳本命令的 npm 命令行縮寫
          "test": "echo \"Error: no test specified\" && exit 1"
          },
          "keywords": [], # 關(guān)鍵詞
          "author": "", # 作者
          "license": "ISC" # 許可證
          }
          可以看到,package.json 文件的內(nèi)容是一個(gè) JSON 對象,對象的每一個(gè)成員就是當(dāng)前項(xiàng)目的一項(xiàng)配置。

          必備屬性(name & version)

          • package.json 中有非常多的配置項(xiàng),其中必須填寫的兩個(gè)字段分別是 name 字段和 version 字段,它們是組成一個(gè) npm 模塊的唯一標(biāo)識

          name 字段

          name 字段定義了模塊的名稱,其命名時(shí)需要遵循官方的一些規(guī)范和建議:

            • 模塊名會成為模塊 url、命令行中的一個(gè)參數(shù)或者一個(gè)文件夾名稱,任何非 url 安全的字符在模塊名中都不能使用(我們可以使用 validate-npm-package-name 包來檢測模塊名是否合法);
            • 語義化模塊名,可以幫助開發(fā)者更快的找到需要的模塊,并且避免意外獲取錯(cuò)誤的模塊;
            • 若模塊名稱中存在一些符號,將符號去除后不得與現(xiàn)有的模塊名重復(fù),例如:由于 react-router-dom 已經(jīng)存在,react.router.domreactrouterdom 都不可以再創(chuàng)建。

          name 字段不能與其他模塊名重復(fù),我們可以執(zhí)行以下命令查看模塊名是否已經(jīng)被使用:

          npm view 
              
               

          如果模塊存在,可以查看該模塊的一些基本信息:

          如果該模塊名從未被使用過,則會拋出 404 錯(cuò)誤:

          或者,我們也可以去 npm 上輸入模塊名,如果搜不到,則可以使用該模塊名。

          version 字段

          npm 包中的模塊版本都需要遵循 SemVer 規(guī)范,該規(guī)范的標(biāo)準(zhǔn)版本號采用 X.Y.Z 的格式,其中 XY 和 Z 均為非負(fù)的整數(shù),且禁止在數(shù)字前方補(bǔ)零:

            • X 是主版本號(major):修改了不兼容的 API
            • Y 是次版本號(minor):新增了向下兼容的功能
            • Z 為修訂號(patch):修正了向下兼容的問題

          當(dāng)某個(gè)版本改動比較大、并非穩(wěn)定而且可能無法滿足預(yù)期的兼容性需求時(shí),我們可能要先發(fā)布一個(gè)先行版本

          先行版本號可以加到主版本號.次版本號.修訂號的后面,通過 - 號連接一連串以句點(diǎn)分隔的標(biāo)識符和版本編譯信息:

            • 內(nèi)部版本(alpha)
            • 公測版本(beta)
            • 正式版本的候選版本rc(即 Release candiate)

          我們可以執(zhí)行以下命令查看模塊的版本:

          npm view 
              
                version 
               # 查看某個(gè)模塊的最新版本
               
          npm view versions # 查看某個(gè)模塊的所有歷史版本
          復(fù)制代碼

          查看 antd 的最新版本:

          查看 antd 的所有歷史版本:

          可以看到,antd 是嚴(yán)格按照 SemVer 規(guī)范來發(fā)版的,版本號是嚴(yán)格按照主版本號.次版本號.修訂號的格式命名和嚴(yán)格遞增的,在發(fā)布的版本改動較大時(shí),還會先發(fā)布alphabetarc等先行版本。

          描述信息(description & keywords)

          • description 字段用于添加模塊的描述信息,便于用戶了解該模塊。
          • keywords 字段用于給模塊添加關(guān)鍵字。
          • 當(dāng)我們使用 npm 檢索模塊時(shí),會對模塊中的 description 字段和 keywords 字段進(jìn)行匹配,寫好 package.json中的 description 和 keywords 將有利于增加我們模塊的曝光率。

          安裝項(xiàng)目依賴(dependencies & devDependencies)

          dependencies字段指定了項(xiàng)目運(yùn)行所依賴的模塊(生產(chǎn)環(huán)境使用),如 antd、 react、 moment等插件庫:

            • 它們是我們生產(chǎn)環(huán)境所需要的依賴項(xiàng),在把項(xiàng)目作為一個(gè) npm 包的時(shí)候,用戶安裝 npm 包時(shí)只會安裝 dependencies 里面的依賴。

          devDependencies 字段指定了項(xiàng)目開發(fā)所需要的模塊(開發(fā)環(huán)境使用),如 webpacktypescriptbabel等:

            • 在代碼打包提交線上時(shí),我們并不需要這些工具,所以我們將它放入devDependencies 中。

          如果一個(gè)模塊不在 package.json 文件之中,我們可以單獨(dú)安裝這個(gè)模塊,并使用相應(yīng)的參數(shù),將其寫入 dependencies 字段/ devDependencies 字段中:

          # 使用 npm
          npm install --save # 寫入 dependencies 屬性
          npm install --save-dev # 寫入 devDependencies 屬性

          # 使用 yarn
          yarn add # 寫入 dependencies 屬性
          yarn add --dev # 寫入 devDependencies 屬性
          復(fù)制代碼
          有了 package.json 文件,開發(fā)直接使用 npm install / yarn install 命令,就會在當(dāng)前目錄中自動安裝所需要的模塊,安裝完成項(xiàng)目所需的運(yùn)行和開發(fā)環(huán)境就配置好了。

          簡化終端命令(scripts)

          scripts 字段是 package.json 中的一種元數(shù)據(jù)功能,它接受一個(gè)對象,對象的屬性為可以通過 npm run 運(yùn)行的腳本,值為實(shí)際運(yùn)行的命令(通常是終端命令),如:
          "scripts": {
          "start": "node index.js"
          },
          將終端命令放入 scripts 字段,既可以記錄它們又可以實(shí)現(xiàn)輕松重用。

          定義項(xiàng)目入口(main)

          main 字段是 package.json 中的另一種元數(shù)據(jù)功能,它可以用來指定加載的入口文件。假如你的項(xiàng)目是一個(gè) npm 包,當(dāng)用戶安裝你的包后,require('my-module') 返回的是 main 字段中所列出文件的 module.exports 屬性。

          當(dāng)不指定main 字段時(shí),默認(rèn)值是模塊根目錄下面的index.js 文件。

          發(fā)布文件配置(files)

          files 字段用于描述我們使用 npm publish 命令后推送到 npm 服務(wù)器的文件列表,如果指定文件夾,則文件夾內(nèi)的所有內(nèi)容都會包含進(jìn)來。
          我們可以查看下載的 antd 的 package.json 的files 字段,內(nèi)容如下:
          "files": [
          "dist",
          "lib",
          "es"
          ],

          可以看到下載后的 antd 包是下面的目錄結(jié)構(gòu):

          另外,我們還可以通過配置一個(gè) .npmignore 文件來排除一些文件, 防止大量的垃圾文件推送到 npm 上。

          定義私有模塊(private)

          一般公司的非開源項(xiàng)目,都會設(shè)置 private 屬性的值為 true,這是因?yàn)?nbsp;npm 拒絕發(fā)布私有模塊,通過設(shè)置該字段可以防止私有模塊被無意間發(fā)布出去。

          指定模塊適用系統(tǒng)(os)

          假如我們開發(fā)了一個(gè)模塊,只能跑在 darwin 系統(tǒng)下,我們需要保證 windows 用戶不會安裝到該模塊,從而避免發(fā)生不必要的錯(cuò)誤。
          這時(shí)候,使用 os 屬性則可以幫助我們實(shí)現(xiàn)以上的需求,該屬性可以指定模塊適用系統(tǒng)的系統(tǒng),或者指定不能安裝的系統(tǒng)黑名單(當(dāng)在系統(tǒng)黑名單中的系統(tǒng)中安裝模塊則會報(bào)錯(cuò)):
          "os" : [ "darwin", "linux" ] # 適用系統(tǒng)
          "os" : [ "!win32" ] # 黑名單

          Tips:在 node 環(huán)境下可以使用 process.platform 來判斷操作系統(tǒng)。

          指定模塊適用 cpu 架構(gòu)(cpu)

          和上面的 os 字段類似,我們可以用 cpu 字段更精準(zhǔn)的限制用戶安裝環(huán)境:
          "cpu" : [ "x64", "ia32" ] # 適用 cpu
          "cpu" : [ "!arm", "!mips" ] # 黑名單

          Tips:在 node 環(huán)境下可以使用 process.arch 來判斷 cpu 架構(gòu)。

          指定項(xiàng)目 node 版本(engines)

          有時(shí)候,新拉一個(gè)項(xiàng)目的時(shí)候,由于和其他開發(fā)使用的 node 版本不同,導(dǎo)致會出現(xiàn)很多奇奇怪怪的問題(如某些依賴安裝報(bào)錯(cuò)、依賴安裝完項(xiàng)目跑步起來等)。

          為了實(shí)現(xiàn)項(xiàng)目開箱即用的偉大理想,這時(shí)候可以使用 package.json 的 engines 字段來指定項(xiàng)目 node 版本:

          "engines": {
          "node": ">= 8.16.0"
          },
          該字段也可以指定適用的 npm 版本:
          "engines": {
          "npm": ">= 6.9.0"
          },
          需要注意的是,engines屬性僅起到一個(gè)說明的作用,當(dāng)用戶版本不符合指定值時(shí)也不影響依賴的安裝。

          自定義命令(bin)

          用過 vue-clicreate-react-app等腳手架的朋友們,不知道你們有沒有好奇過,為什么安裝這些腳手架后,就可以使用類似 vue create/create-react-app之類的命令,其實(shí)這和 package.json 中的 bin 字段有關(guān)。

          bin 字段用來指定各個(gè)內(nèi)部命令對應(yīng)的可執(zhí)行文件的位置。當(dāng)package.json 提供了 bin 字段后,即相當(dāng)于做了一個(gè)命令名和本地文件名的映射。

          當(dāng)用戶安裝帶有 bin 字段的包時(shí),

            • 如果是全局安裝,npm 將會使用符號鏈接把這些文件鏈接到/usr/local/node_modules/.bin/
            • 如果是本地安裝,會鏈接到./node_modules/.bin/

          舉個(gè) ?,如果要使用 my-app-cli 作為命令時(shí),可以配置以下 bin 字段:

          "bin": {
          "my-app-cli": "./bin/cli.js"
          }
          上面代碼指定,my-app-cli 命令對應(yīng)的可執(zhí)行文件為 bin 子目錄下的 cli.js,因此在安裝了 my-app-cli 包的項(xiàng)目中,就可以很方便地利用 npm執(zhí)行腳本:
          "scripts": {
          start: 'node node_modules/.bin/my-app-cli'
          }

          咦,怎么看起來和 vue create/create-react-app之類的命令不太像?原因:

            • 當(dāng)需要 node 環(huán)境時(shí)就需要加上 node 前綴
            • 如果加上 node 前綴,就需要指定 my-app-cli 的路徑 -> node_modules/.bin,否則 node my-app-cli會去查找當(dāng)前路徑下的 my-app-cli.js,這樣肯定是不對。

          若要實(shí)現(xiàn)像 vue create/create-react-app之類的命令一樣簡便的方式,則可以在上文提到的 bin 子目錄下可執(zhí)行文件cli.js 中的第一行寫入以下命令:

          #!/usr/bin/env node
          這行命令的作用是告訴系統(tǒng)用 node 解析,這樣命令就可以簡寫成 my-app-cli 了。

          React 項(xiàng)目相關(guān)

          設(shè)置應(yīng)用根路徑(homepage)

          當(dāng)我們使用 create-react-app 腳手架搭建的 React 項(xiàng)目,默認(rèn)是使用內(nèi)置的 webpack 配置,當(dāng)package.json 中不配置 homepage 屬性時(shí),build 打包之后的文件資源應(yīng)用路徑默認(rèn)是  /,如下圖:

          一般來說,我們打包的靜態(tài)資源會部署在 CDN 上,為了讓我們的應(yīng)用知道去哪里加載資源,則需要我們設(shè)置一個(gè)根路徑,這時(shí)可以通過 package.json 中的 homepage 字段設(shè)置應(yīng)用的根路徑。

          當(dāng)我們設(shè)置了 homepage 屬性后:

          {
          "homepage": "https://xxxx.cdn/my-project",
          }

          打包后的資源路徑就會加上 homepage 的地址:

          開發(fā)環(huán)境解決跨域問題(proxy)

          在做前后端分離的項(xiàng)目的時(shí)候,調(diào)用接口時(shí)則會遇到跨域的問題,當(dāng)在開發(fā)環(huán)境中時(shí),可以通過配置 package.json 中的 proxy 來解決跨域問題,配置如下:
          {
          "proxy": "http://localhost:4000" // 配置你要請求的服務(wù)器地址
          }
          注意,當(dāng) create-react-app 的版本高于 2.0 版本的時(shí)候在 package.json 中只能配置string 類型,這意味著如果要使用 package.json 來解決跨域問題,則只能代理一個(gè)服務(wù)器地址。
          如果要代理多個(gè)服務(wù)器地址時(shí),則需要安裝 http-proxy-middleware ,在 src 目錄下新建 setupProxy.js :
          const proxy = require("http-proxy-middleware");

          module.exports = function(app) {
          app.use(
          proxy("/base", {
          target: "http://localhost:4000",
          changeOrigin: true
          })
          );
          app.use(
          proxy("/fans", {
          target: "http://localhost:5000",
          changeOrigin: true
          })
          );
          };

          根據(jù)開發(fā)環(huán)境采用不同的全局變量值(自定義字段)

          假設(shè)有這么一個(gè)組件,當(dāng)組件被點(diǎn)擊時(shí),在開發(fā)環(huán)境時(shí)是跳轉(zhuǎn)測試環(huán)境的 sentry 地址,在正式環(huán)境時(shí)則跳轉(zhuǎn)正式環(huán)境的 sentry 地址。
          首先,通過配置前面提到的 scripts 字段,實(shí)現(xiàn)環(huán)境變量(NODE_ENV)的設(shè)置:
          "scripts": {
          "start": "NODE_ENV=development node scripts/start.js",
          "build": "NODE_ENV=production node scripts/build.js",
          },
          項(xiàng)目啟動起來后,在代碼中我們可以通過 process.env.NODE_ENV 訪問到 NODE_ENV 的值。
          方案一
          我們可以在組件中寫類似以下的判斷代碼,根據(jù)不同環(huán)境給 sentryUrl 設(shè)置不同的值:
          let sentryUrl;
          if (process.env.NODE_ENV === 'development') {
          sentryUrl = 'test-sentry.xxx.com';
          } else {
          sentryUrl = 'sentry.xxx.com';
          }

          這么做好像沒毛病,但是深入一想,如果有多個(gè)組件,要根據(jù)不同的環(huán)境使用不同的服務(wù)(多種服務(wù))地址,如果按照上面的寫法,項(xiàng)目中將存在許多重復(fù)的判斷代碼,且當(dāng)服務(wù)地址發(fā)生變化時(shí),包含這些服務(wù)地址的組件都需要相應(yīng)的做改動,這樣明顯是不合理的。

          方案二

          解決方案:相關(guān)服務(wù)的地址配置在 package.json中,同時(shí)修改項(xiàng)目的 webpack 配置。

          注:修改項(xiàng)目的 webpack 配置需要 eject 項(xiàng)目的 webpack 配置(更多細(xì)節(jié)可閱讀 ?:react + typescript 項(xiàng)目的定制化過程)。

          在項(xiàng)目根目錄下使用 yarn eject 成功 eject 出配置后,可以發(fā)現(xiàn)項(xiàng)目目錄的變化如下:

          如果需要定制化項(xiàng)目,一般就是在 config 目錄下對默認(rèn)的 webpack 配置進(jìn)行修改,在這里我們需要關(guān)注 config/path.js 和 config/env.js 兩個(gè)文件:

            • env.js 的主要目的在于讀取 env 配置文件并將 env 的配置信息給到全局變量 process.env ;
            • path.js 的主要目的在于為項(xiàng)目提供各種路徑,包括構(gòu)建路徑、 public 路徑等。

          由于本文的重點(diǎn)不是學(xué)習(xí) webpack 配置,這里僅介紹如何實(shí)現(xiàn)【根據(jù)開發(fā)環(huán)境采用不同的全局變量值】的功能。

          首先,需要在 package.json 中配置以下內(nèi)容:

          "scripts": {
          "start": "NODE_ENV=development node scripts/start.js",
          "build": "NODE_ENV=production node scripts/build.js",
          },
          "sentryPath": {
          "dev": "https://test-sentry.xxx.com",
          "prod": "https://sentry.xxx.com"
          }
          然后,修改 path.js 文件,內(nèi)容如下:
          // 重寫 getPublicUrl 方法
          const getPublicUrl = (appPackageJson, pathName) => {
          let path;
          switch (process.env.DEPLOY_ENV) {
          case 'development':
          path = require(appPackageJson)[pathName].dev;
          break;
          case 'production':
          path = require(appPackageJson)[pathName].prod;
          break;
          default:
          path = envPublicUrl || require(appPackageJson).homepage;
          }
          return path;
          }

          // 新增 getSentryPath 方法
          const getSentryPath = (appPackageJson) => {
          return getPublicUrl(appPackageJson, 'sentryPath');
          }

          // config after eject: we're in ./config/
          module.exports = {
          ...,
          sentryUrl: getSentryPath(resolveApp('package.json')), // 新增
          };
          最后,修改 env.js 文件,內(nèi)容如下:
          // 修改 getClientEnvironment 方法
          function getClientEnvironment(publicUrl) {
          const raw = Object.keys(process.env)
          .filter(key => REACT_APP.test(key))
          .reduce(
          (env, key) => {
          ...
          },
          {
          NODE_ENV: process.env.NODE_ENV || 'development',
          PUBLIC_URL: publicUrl,
          SENTRY_URL: paths.sentryUrl // 新增
          }
          );

          const stringified = {
          ...
          };
          return { raw, stringified };
          }
          通過上面的配置,我們就可以在組件中通過 process.env.SENTRY_URL 獲取到 sentry 服務(wù)的地址了,雖然看起來比方案一繁瑣,但是這種收益是長期的,如要新增一個(gè)  sonarqube 服務(wù),同理實(shí)現(xiàn)即可,通過使用 package.json 也可以清楚的看到當(dāng)前服務(wù)在不同環(huán)境下使用的地址。

          總結(jié) ?

          本文介紹了 package.json 的多種常見的配置字段及作用,并通過例子加深大家對 package.json這些字段的理解。
          除了一些常用字段,還介紹了在React 項(xiàng)目中 package.json 文件能實(shí)現(xiàn)的一些功能進(jìn)行介紹。

          以上內(nèi)容如有遺漏錯(cuò)誤,歡迎留言 ?? 指出,一起進(jìn)步 ???

          如果覺得本文對你有幫助,?? 留下你寶貴的 ?

          參考資料 ?

          1. Creating a package.json file
          2. package.json bin的作用
          3. 在開發(fā)環(huán)境中代理 API 請求
          4. react + typescript 項(xiàng)目的定制化過程
          5. React學(xué)習(xí)筆記

          Dotnet9網(wǎng)站常駐編輯


             

          長按關(guān)注我,

          歡迎技術(shù)交流!

          -好東西要轉(zhuǎn)發(fā),設(shè)為"星標(biāo)"★搶先看-

          點(diǎn)擊閱讀原文,查看Dotnet9站點(diǎn)更多博文。

          瀏覽 69
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評論
          圖片
          表情
          推薦
          點(diǎn)贊
          評論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  色婷婷国产综合 | 激情草逼 | 俺去也在线视频 | 中国女人一级片 | 在线三级片网站 |