使用typescript+webpack構建一個js庫的示例詳解_第1頁
使用typescript+webpack構建一個js庫的示例詳解_第2頁
使用typescript+webpack構建一個js庫的示例詳解_第3頁
使用typescript+webpack構建一個js庫的示例詳解_第4頁
使用typescript+webpack構建一個js庫的示例詳解_第5頁
已閱讀5頁,還剩19頁未讀 繼續免費閱讀

下載本文檔

版權說明:本文檔由用戶提供并上傳,收益歸屬內容提供方,若內容存在侵權,請進行舉報或認領

文檔簡介

第使用typescript+webpack構建一個js庫的示例詳解目錄入口文件tsconfig配置webpack配置文件webpack入口文件配置webpack為typescript和less文件配置各自的loaderwebpack的output配置運行webpack進行打包測試驗證輸出esm模塊已經輸出了umd格式的js了,為什么還要輸出esm模塊----TreeShaking用tsc輸出esm和類型聲明文件package.json中添加exports配置聲明模塊導出路徑完善package.json文件用api-extractor提取出干凈的.d.ts配置使用APIextractor更新package.json用@internal標注只希望在內部使用的class小結記錄使用typescript配合webpack打包一個javascriptlibrary的配置過程.

目標是構建一個可以同時支持CommonJs,esm,amd這個幾個js模塊系統的javascript庫,然后還有一個單獨打包出一個css的樣式文件的需求.

為此以構建一個名為loaf的javascript庫為例;首先新建項目文件目錄loaf,并進入此文件目錄執行npminit命令,然后按照控制臺的提示輸入對應的信息,完成后就會在loaf目錄下得到一個package.json文件

然后使用npmi命令安裝所需的依賴

npmi-Dwebpackwebpack-clitypescriptbabel-loader@babel/core@babel/preset-env@babel/preset-typescriptts-node@types/node@types/webpackmini-css-extract-plugincss-minimizer-webpack-pluginlessless-loaderterser-webpack-plugin

依賴說明

webpackwebpack-cli:webpack打包工具和webpack命令行接口typescript:用于支持typescript語言babel-loader@babel/core@babel/preset-env@babel/preset-typescript:babel相關的東西,主要是需要babel-loader將編寫的typescript代碼轉譯成es5或es6已獲得更好的瀏覽器兼容性ts-node@types/node@types/webpack:安裝這幾個包是為了能用typescript編寫webpack配置文件(webpack.config.ts)mini-css-extract-pluginlessless-loader:編譯提取less文件到單獨的css文件的相關依賴css-minimizer-webpack-pluginterser-webpack-plugin:用于最小化js和css文件尺寸的webpack插件

入口文件

通常使用index.ts作為入口,并將其放到src目錄下,由于有輸出樣式文件的需求,所以還要新建styles/index.less

mkdirsrctouchsrc/index.ts

mkdirsrc/stylestouchsrc/styles/index.less

tsconfig配置

新建tsconfig.json文件

touchtsconfig.json

填入以下配置(部分選項配有注釋):

{

"compilerOptions":{

"outDir":"dist/lib",

"sourceMap":false,

"noImplicitAny":true,

"module":"commonjs",

//開啟這個選項,可以讓你直接通過`import`的方式來引用commonjs模塊

//這樣你的代碼庫中就可以統一的使用import導入依賴了,而不需要另外再使用require導入commonjs模塊

"esModuleInterop":true,

//是否允許合成默認導入

//開啟后,依賴的模塊如果沒有導出默認的模塊

//那么typescript會幫你給該模塊自動合成一個默認導出讓你可以通過默認導入的方式引用該模塊

"allowSyntheticDefaultImports":true,

//是否生成`.d.ts`的類型聲明文件

"declaration":true,

//輸出的目標js版本,這里用es6,然后配和babel進行轉譯才以獲得良好的瀏覽器兼容

"target":"es6",

"allowJs":true,

"moduleResolution":"node",

"lib":["es2015","dom"],

"declarationMap":true,

//啟用嚴格的null檢查

"strictNullChecks":true,

//啟用嚴格的屬性初始化檢查

//啟用后類屬性必須顯示標注為可空或賦一個非空的初始值

"strictPropertyInitialization":true

"exclude":["node_modules"],

"include":["src/**/*"]

}

webpack配置文件

創建webpack.config.ts

touchwebpack.config.ts

webpack.config.ts

importpathfrom"path";

import{Configuration,Entry}from"webpack";

importMiniCssExtractPluginfrom'mini-css-extract-plugin';

importCssMinimizerfrom'css-minimizer-webpack-plugin';

importTerserPluginfrom'terser-webpack-plugin'

constisProd=process.env.NODE_ENV==='production';

*這里用到了webpack的[Multiplefiletypesperentry](/guides/entry-advanced/)特性

*注意`.less`入口文件必須放在`.ts`文件前*/

constentryFiles:string[]=['./src/styles/index.less','./src/index.ts'];

constentry:Entry={

index:entryFiles,

'index.min':entryFiles,

constconfig:Configuration={

entry,

optimization:{

minimize:true,

minimizer:[

newTerserPlugin({test:/.min.js$/}),

newCssMinimizer({

test:/.min.css$/,

module:{

rules:[

test:/.ts$/,

loader:'babel-loader',

exclude:/node_modules/,

options:{

presets:['@babel/env','@babel/typescript'],

test:/.less$/,

use:[

isProdMiniCssExtractPlugin.loader:'style-loader',

loader:'css-loader',

'postcss-loader',

'less-loader',

output:{

path:path.resolve(__dirname,'dist/umd'),

library:{

type:'umd',

name:{

amd:'loaf',

commonjs:'loaf',

root:'loaf',

resolve:{

extensions:['.ts','.less'],

devtool:'source-map',

plugins:[

newMiniCssExtractPlugin({

filename:'[name].css',

exportdefaultconfig;

webpack入口文件配置

...

constisProd=process.env.NODE_ENV==='production';

*這里用到了webpack的[Multiplefiletypesperentry](/guides/entry-advanced/)特性

*注意`.less`入口文件必須放在`.ts`文件前*/

constentryFiles:string[]=['./src/styles/index.less','./src/index.ts'];

constentry:Entry={

index:entryFiles,

'index.min':entryFiles,

constconfig:Configuration={

entry,

...

在上面的webpack.config.json中,我們配置了兩個入口分別是index和index.min,不難看出,多出的一個index.min入口是為了經過壓縮后js和css文件,在生產環境使用一般都會使用.min.js結尾的文件以減少網絡傳輸時的尺寸;實現這個還需要結合optimization相關配置,如下:

optimization:{

minimize:true,

minimizer:[

newTerserPlugin({test:/.min.js$/}),

newCssMinimizer({

test:/.min.css$/,

},

另外,index和index.min的值都是相同的entryFiles對象,這個對象是一個字符串數組,里面放的就是我們的入口文件相對路徑,這里一定要注意把./src/styles/index.less置于./src/index.ts之前。

webpack為typescript和less文件配置各自的loader

配置完入口后,就需要為typescript和less代碼配置各自的loader

module:{

rules:[

test:/.ts$/,

loader:'babel-loader',

exclude:/node_modules/,

options:{

presets:['@babel/env','@babel/typescript'],

test:/.less$/,

use:[

isProdMiniCssExtractPlugin.loader:'style-loader',

loader:'css-loader',

'postcss-loader',

'less-loader',

},

mini-css-extract-pluginlessless-loader:編譯提取less文件到單獨的css文件的相關依賴

上面的配置為.ts結尾的文件配置了babel-loader;為.less結尾的文件配置一串loader,使用了use,use中的loader的執行順序是從后往前的,上面less的配置就是告訴webpack遇到less文件時,一次用less-loader-postcss-loader-css-loader-生產環境用MiniCssExtractPlugin.loader()否則用style-loader;

MiniCssExtractPlugin.loader使用前要先在plugins進行初始化

...

constconfig={

plugins:[

newMiniCssExtractPlugin({

filename:'[name].css',

...

webpack的output配置

...

constconfig={

output:{

path:path.resolve(__dirname,'dist/umd'),

library:{

type:'umd',

name:{

amd:'loaf',

commonjs:'loaf',

root:'loaf',

...

這里配置webpack以umd的方式輸出到相對目錄dist/umd目錄中,umd是UniversalModuleDefinition(通用模塊定義)的縮寫,umd格式輸出library允許用戶通過commonjs,AMD,scriptsrc=...的方式對library進行引用可以為不同的模塊系統配置不同的導出模塊名供客戶端來進行引用;由于這里的導出模塊名都是loaf,所以也可以直接設置成loaf.

運行webpack進行打包

現在回到最開始通過npminit生成的package.json文件,在修改其內容如下

{

"name":"loaf",

"version":"1.0.0",

"description":"Ademoshowshowtocreatebuildajavascriptlibrarywithwebpacktypescript",

"main":"index.js",

"scripts":{

"build:umd":"webpack-cwebpack.config.ts--node-envproduction--envNODE_ENV=production",

"test":"npmruntest"

"keywords":[

"demo"

"author":"laggage",

"license":"MIT",

"devDependencies":{

"@babel/core":"^7.18.6",

"@babel/preset-env":"^7.18.6",

"@babel/preset-typescript":"^7.18.6",

"@types/node":"^18.0.0",

"@types/webpack":"^5.28.0",

"babel-loader":"^8.2.5",

"css-loader":"^6.7.1",

"css-minimizer-webpack-plugin":"^4.0.0",

"less":"^4.1.3",

"less-loader":"^11.0.0",

"mini-css-extract-plugin":"^2.6.1",

"postcss-loader":"^7.0.0",

"style-loader":"^3.3.1",

"terser-webpack-plugin":"^5.3.3",

"ts-node":"^10.8.2",

"typescript":"^4.7.4",

"webpack":"^5.73.0",

"webpack-cli":"^4.10.0"

}

新增了一個腳本命令build:umd:webpack-cwebpack.config.ts--node-envproduction--envNODE_ENV=production,然后命令行到項目目錄下執行npmrunbuild:umd,不出意外應該就構建成功了,此時生成的dist目錄結構如下

dist

└──umd

├──index.css

├──index.js

├──index.js.map

├──index.min.css

├──index.min.js

└──index.min.js.map

1directory,6files

測試驗證

新建demo.html進行測試

mkdirdemotouchdemo/demo.html

demo/demo.html

!DOCTYPEhtml

htmllang="en"

head

metacharset="UTF-8"

metahttp-equiv="X-UA-Compatible"content="IE=edge"

metaname="viewport"content="width=device-width,initial-scale=1.0"

titleDocument/title

/head

body

scriptsrc="../dist/umd/index.js"/script

scripttype="text/javascript"

console.log(loaf,'\n',loaf.Foo)

/script

/body

/html

用瀏覽器打開demo.html,然后F12打開控制臺,可以看到如下輸出則說明初步達成了目標:

Module{__esModule:true,Symbol(Symbol.toStringTag):'Module'}

demo.html:13?Foo(){

var_bar=arguments.length0arguments[0]!==undefinedarguments[0]:newBar();

src_classCallCheck(this,Foo);

this._bar=_bar;

}

輸出esm模塊

完成上面的步驟后,我們已經到了一個umd模塊的輸出,相關文件都在dist/umd目錄下;其中包含可供CommonJsESMAMD模塊系統和script標簽使用的umd格式的javascript文件和一個單獨的css樣式文件.

已經輸出了umd格式的js了,為什么還要輸出esm模塊----TreeShaking

TreeshakingisatermcommonlyusedintheJavaScriptcontextfordead-codeelimination.ItreliesonthestaticstructureofES2015modulesyntax,i.e.importandexport.ThenameandconcepthavebeenpopularizedbytheES2015modulebundlerrollup.

此庫的使用者也使用了類似webpack之類的支持TreeShaking

的模塊打包工具,需要讓使用者的打包工具能對這個js庫loaf進行死代碼優化TreeShaking

從webpack文檔中看出,tree-shaking依賴于ES2015(ES2015modulesyntax,ES2015=ES6)的模塊系統,tree-shaking可以對打包體積有不錯優化,所以為了支持使用者進行tree-shaking,輸出esm模塊(esm模塊就是指ES2015modulesyntax)是很有必要的.

用tsc輸出esm和類型聲明文件

tsc-ptsconfig.json--declarationDir./dist/typings-mes6--outDirdist/lib-esm

上面的命令使用typescript編譯器命令行接口tsc輸出了ES6模塊格式的javascript文件到dist/lib-esm目錄下

將這個目錄加入到package.json的scripts配置中:

package.json

{

"name":"loaf",

"version":"1.0.0",

"description":"Ademoshowshowtocreatebuildajavascriptlibrarywithwebpacktypescript",

"main":"index.js",

"scripts":{

"build:umd":"webpack-cwebpack.config.ts--node-envproduction--envNODE_ENV=production",

"build:lib-esm":"tsc-ptsconfig.json--declarationDir./dist/typings-mes6--outDirdist/lib-esm",

"test":"npmruntest"

"keywords":[

"demo"

"author":"laggage",

"license":"MIT",

"devDependencies":{

"@babel/core":"^7.18.6",

"@babel/preset-env":"^7.18.6",

"@babel/preset-typescript":"^7.18.6",

"@types/node":"^18.0.0",

"@types/webpack":"^5.28.0",

"babel-loader":"^8.2.5",

"css-loader":"^6.7.1",

"css-minimizer-webpack-plugin":"^4.0.0",

"less":"^4.1.3",

"less-loader":"^11.0.0",

"mini-css-extract-plugin":"^2.6.1",

"postcss-loader":"^7.0.0",

"style-loader":"^3.3.1",

"terser-webpack-plugin":"^5.3.3",

"ts-node":"^10.8.2",

"typescript":"^4.7.4",

"webpack":"^5.73.0",

"webpack-cli":"^4.10.0"

}

然后運行:npmrunbuild:lib-esm,此時dist目錄結構如下:

dist

├──lib-esm

│├──bar.js

│└──index.js

├──typings

│├──bar.d.ts

│├──bar.d.ts.map

│├──index.d.ts

│└──index.d.ts.map

└──umd

├──index.css

├──index.js

├──index.js.map

├──index.min.css

├──index.min.js

└──index.min.js.map

3directories,12files

多出了兩個子目錄分別為lib-esm和typings,分別放著es6模塊格式的javascript輸出文件和typescript類型聲明文件.

完善package.json文件

到目前為止,package.json的scripts配置中,已經有了build:umd和build:lib-esm用于構建umd格式的輸出和esm格式的輸出,現在我們再向添加一個build用來組合build:umd和build:lib-esm并進行最終的構建,再次之前先安裝一個依賴shx,用于跨平臺執行一些shell腳本:npmi-Dshx;

更新package.json文件:

package.json

{

"name":"loaf",

"version":"1.0.0",

"description":"Ademoshowshowtocreatebuildajavascriptlibrarywithwebpacktypescript",

"main":"index.js",

"scripts":{

"build":"shxrm-rfdist/**npmrunbuild:umdnpmrunbuild:lib-esm",

"build:umd":"webpack-cwebpack.config.ts--node-envproduction--envNODE_ENV=production",

"build:lib-esm":"tsc-ptsconfig.json--declarationDir./dist/typings-mes6--outDirdist/lib-esm",

"test":"npmruntest"

"keywords":[

"demo"

"author":"laggage",

"license":"MIT",

"devDependencies":{

"@babel/core":"^7.18.6",

"@babel/preset-env":"^7.18.6",

"@babel/preset-typescript":"^7.18.6",

"@types/node":"^18.0.0",

"@types/webpack":"^5.28.0",

"babel-loader":"^8.2.5",

"css-loader":"^6.7.1",

"css-minimizer-webpack-plugin":"^4.0.0",

"less":"^4.1.3",

"less-loader":"^11.0.0",

"mini-css-extract-plugin":"^2.6.1",

"postcss-loader":"^7.0.0",

"shx":"^0.3.4",

"style-loader":"^3.3.1",

"terser-webpack-plugin":"^5.3.3",

"ts-node":"^10.8.2",

"typescript":"^4.7.4",

"webpack":"^5.73.0",

"webpack-cli":"^4.10.0"

}

package.json文件生成typescript聲明文件所在的路徑(可以參考typescript官網:Includingdeclarationsinyournpmpackage):

package.json

{

"name":"loaf",

"version":"1.0.0",

"description":"Ademoshowshowtocreatebuildajavascriptlibrarywithwebpacktypescript",

"main":"index.js",

"typings":"./typings",

"scripts":{

"build":"shxrm-rfdist/**npmrunbuild:umdnpmrunbuild:lib-esm",

"build:umd":"webpack-cwebpack.config.ts--node-envproduction--envNODE_ENV=production",

"build:lib-esm":"tsc-ptsconfig.json--declarationDir./dist/typings-mes6--outDirdist/lib-esm",

"test":"npmruntest"

"keywords":[

"demo"

"author":"laggage",

"license":"MIT",

"devDependencies":{

"@babel/core":"^7.18.6",

"@babel/preset-env":"^7.18.6",

"@babel/preset-typescript":"^7.18.6",

"@types/node":"^18.0.0",

"@types/webpack":"^5.28.0",

"babel-loader":"^8.2.5",

"css-loader":"^6.7.1",

"css-minimizer-webpack-plugin":"^4.0.0",

"less":"^4.1.3",

"less-loader":"^11.0.0",

"mini-css-extract-plugin":"^2.6.1",

"postcss-loader":"^7.0.0",

"shx":"^0.3.4",

"style-loader":"^3.3.1",

"terser-webpack-plugin":"^5.3.3",

"ts-node":"^10.8.2",

"typescript":"^4.7.4",

"webpack":"^5.73.0",

"webpack-cli":"^4.10.0"

}

package.json中添加exports配置聲明模塊導出路徑

package.json中的exports字段用于告訴使用者引用此庫時從哪里尋找對應的模塊文件.比如使用者可能通過esm模塊引用此庫:

import{Foo}from'loaf';

constfoo=newFoo();

此時如果我們的package.json中沒有指定exports字段,那么模塊系統會去尋找node_modules/index.js,結果肯定是找不到的,因為我們真正的esm格式的輸出文件應該是在node_modules/loaf/lib-esm中的

于是我們可以這樣來配置exports:

package.json

{

"name":"loaf",

"version":"1.0.0",

"description":"Ademoshowshowtocreatebuildajavascriptlibrarywithwebpacktypescript",

"main":"index.js",

"typings":"./typings",

"exports":{

"./*":"./lib-esm/*",

"./umd/*":"./umd"

"scripts":{

"build":"shxrm-rfdist/**npmrunbuild:umdnpmrunbuild:lib-esm",

"build:umd":"webpack-cwebpack.config.ts--node-envproduction--envNODE_ENV=production",

"build:lib-esm":"tsc-ptsconfig.json--declarationDir./dist/typings-mes6--outDirdist/lib-esm",

"test":"npmruntest"

"keywords":[

"demo"

"author":"laggage",

"license":"MIT",

"devDependencies":{

"@babel/core":"^7.18.6",

"@babel/preset-env":"^7.18.6",

"@babel/preset-typescript":"^7.18.6",

"@types/node":"^18.0.0",

"@types/webpack":"^5.28.0",

"babel-loader":"^8.2.5",

"css-loader":"^6.7.1",

"css-minimizer-webpack-plugin":"^4.0.0",

"less":"^4.1.3",

"less-loader":"^11.0.0",

"mini-css-extract-plugin":"^2.6.1",

"postcss-loader":"^7.0.0",

"shx":"^0.3.4",

"style-loader":"^3.3.1",

"terser-webpack-plugin":"^5.3.3",

"ts-node":"^10.8.2",

"typescript":"^4.7.4",

"webpack":"^5.73.0",

"webpack-cli":"^4.10.0"

}

用api-extractor提取出干凈的.d.ts

在上面的用tsc輸出esm和類型聲明文件這一段中,我們通過tsc命令輸出了typescript了類型聲明文件到dist/types目錄下,這個目錄下有兩個.d.ts文件,分別是bar.d.ts和foo.d.ts,通常是希望這些聲明文件都在一個文件index.d.ts中的,如果他們分散開了,以本庫為例,如果我要使用本庫中的Bar類,那么我可能需要這樣來導入:

import{Bar}from'loaf/typings/bar';

我不覺得的這種導入方式是好的做法,理想的導入方式應該像下面這樣:

import{Bar}from'loaf';

所以接下來,還要引入微軟提供的api-extracto

溫馨提示

  • 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯系上傳者。文件的所有權益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網頁內容里面會有圖紙預覽,若沒有圖紙預覽就沒有圖紙。
  • 4. 未經權益所有人同意不得將文件中的內容挪作商業或盈利用途。
  • 5. 人人文庫網僅提供信息存儲空間,僅對用戶上傳內容的表現方式做保護處理,對用戶上傳分享的文檔內容本身不做任何修改或編輯,并不能對任何下載內容負責。
  • 6. 下載文件中如有侵權或不適當內容,請與我們聯系,我們立即糾正。
  • 7. 本站不保證下載資源的準確性、安全性和完整性, 同時也不承擔用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。

評論

0/150

提交評論