使用typescript+webpack構(gòu)建一個(gè)js庫(kù)的示例詳解_第1頁(yè)
使用typescript+webpack構(gòu)建一個(gè)js庫(kù)的示例詳解_第2頁(yè)
使用typescript+webpack構(gòu)建一個(gè)js庫(kù)的示例詳解_第3頁(yè)
使用typescript+webpack構(gòu)建一個(gè)js庫(kù)的示例詳解_第4頁(yè)
使用typescript+webpack構(gòu)建一個(gè)js庫(kù)的示例詳解_第5頁(yè)
已閱讀5頁(yè),還剩19頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

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

目標(biāo)是構(gòu)建一個(gè)可以同時(shí)支持CommonJs,esm,amd這個(gè)幾個(gè)js模塊系統(tǒng)的javascript庫(kù),然后還有一個(gè)單獨(dú)打包出一個(gè)css的樣式文件的需求.

為此以構(gòu)建一個(gè)名為loaf的javascript庫(kù)為例;首先新建項(xiàng)目文件目錄loaf,并進(jìn)入此文件目錄執(zhí)行npminit命令,然后按照控制臺(tái)的提示輸入對(duì)應(yīng)的信息,完成后就會(huì)在loaf目錄下得到一個(gè)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

依賴說(shuō)明

webpackwebpack-cli:webpack打包工具和webpack命令行接口typescript:用于支持typescript語(yǔ)言babel-loader@babel/core@babel/preset-env@babel/preset-typescript:babel相關(guān)的東西,主要是需要babel-loader將編寫(xiě)的typescript代碼轉(zhuǎn)譯成es5或es6已獲得更好的瀏覽器兼容性ts-node@types/node@types/webpack:安裝這幾個(gè)包是為了能用typescript編寫(xiě)webpack配置文件(webpack.config.ts)mini-css-extract-pluginlessless-loader:編譯提取less文件到單獨(dú)的css文件的相關(guān)依賴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

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

{

"compilerOptions":{

"outDir":"dist/lib",

"sourceMap":false,

"noImplicitAny":true,

"module":"commonjs",

//開(kāi)啟這個(gè)選項(xiàng),可以讓你直接通過(guò)`import`的方式來(lái)引用commonjs模塊

//這樣你的代碼庫(kù)中就可以統(tǒng)一的使用import導(dǎo)入依賴了,而不需要另外再使用require導(dǎo)入commonjs模塊

"esModuleInterop":true,

//是否允許合成默認(rèn)導(dǎo)入

//開(kāi)啟后,依賴的模塊如果沒(méi)有導(dǎo)出默認(rèn)的模塊

//那么typescript會(huì)幫你給該模塊自動(dòng)合成一個(gè)默認(rèn)導(dǎo)出讓你可以通過(guò)默認(rèn)導(dǎo)入的方式引用該模塊

"allowSyntheticDefaultImports":true,

//是否生成`.d.ts`的類(lèi)型聲明文件

"declaration":true,

//輸出的目標(biāo)js版本,這里用es6,然后配和babel進(jìn)行轉(zhuǎn)譯才以獲得良好的瀏覽器兼容

"target":"es6",

"allowJs":true,

"moduleResolution":"node",

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

"declarationMap":true,

//啟用嚴(yán)格的null檢查

"strictNullChecks":true,

//啟用嚴(yán)格的屬性初始化檢查

//啟用后類(lèi)屬性必須顯示標(biāo)注為可空或賦一個(gè)非空的初始值

"strictPropertyInitialization":true

"exclude":["node_modules"],

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

}

webpack配置文件

創(chuàng)建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中,我們配置了兩個(gè)入口分別是index和index.min,不難看出,多出的一個(gè)index.min入口是為了經(jīng)過(guò)壓縮后js和css文件,在生產(chǎn)環(huán)境使用一般都會(huì)使用.min.js結(jié)尾的文件以減少網(wǎng)絡(luò)傳輸時(shí)的尺寸;實(shí)現(xiàn)這個(gè)還需要結(jié)合optimization相關(guān)配置,如下:

optimization:{

minimize:true,

minimizer:[

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

newCssMinimizer({

test:/.min.css$/,

},

另外,index和index.min的值都是相同的entryFiles對(duì)象,這個(gè)對(duì)象是一個(gè)字符串?dāng)?shù)組,里面放的就是我們的入口文件相對(duì)路徑,這里一定要注意把./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文件到單獨(dú)的css文件的相關(guān)依賴

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

MiniCssExtractPlugin.loader使用前要先在plugins進(jìn)行初始化

...

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以u(píng)md的方式輸出到相對(duì)目錄dist/umd目錄中,umd是UniversalModuleDefinition(通用模塊定義)的縮寫(xiě),umd格式輸出library允許用戶通過(guò)commonjs,AMD,scriptsrc=...的方式對(duì)library進(jìn)行引用可以為不同的模塊系統(tǒng)配置不同的導(dǎo)出模塊名供客戶端來(lái)進(jìn)行引用;由于這里的導(dǎo)出模塊名都是loaf,所以也可以直接設(shè)置成loaf.

運(yùn)行webpack進(jìn)行打包

現(xiàn)在回到最開(kāi)始通過(guò)npminit生成的package.json文件,在修改其內(nèi)容如下

{

"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"

}

新增了一個(gè)腳本命令build:umd:webpack-cwebpack.config.ts--node-envproduction--envNODE_ENV=production,然后命令行到項(xiàng)目目錄下執(zhí)行npmrunbuild:umd,不出意外應(yīng)該就構(gòu)建成功了,此時(shí)生成的dist目錄結(jié)構(gòu)如下

dist

└──umd

├──index.css

├──index.js

├──index.js.map

├──index.min.css

├──index.min.js

└──index.min.js.map

1directory,6files

測(cè)試驗(yàn)證

新建demo.html進(jìn)行測(cè)試

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

用瀏覽器打開(kāi)demo.html,然后F12打開(kāi)控制臺(tái),可以看到如下輸出則說(shuō)明初步達(dá)成了目標(biāo):

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模塊

完成上面的步驟后,我們已經(jīng)到了一個(gè)umd模塊的輸出,相關(guān)文件都在dist/umd目錄下;其中包含可供CommonJsESMAMD模塊系統(tǒng)和script標(biāo)簽使用的umd格式的javascript文件和一個(gè)單獨(dú)的css樣式文件.

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

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

此庫(kù)的使用者也使用了類(lèi)似webpack之類(lèi)的支持TreeShaking

的模塊打包工具,需要讓使用者的打包工具能對(duì)這個(gè)js庫(kù)loaf進(jìn)行死代碼優(yōu)化TreeShaking

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

用tsc輸出esm和類(lèi)型聲明文件

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

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

將這個(gè)目錄加入到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"

}

然后運(yùn)行:npmrunbuild:lib-esm,此時(shí)dist目錄結(jié)構(gòu)如下:

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

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

完善package.json文件

到目前為止,package.json的scripts配置中,已經(jīng)有了build:umd和build:lib-esm用于構(gòu)建umd格式的輸出和esm格式的輸出,現(xiàn)在我們?cè)傧蛱砑右粋€(gè)build用來(lái)組合build:umd和build:lib-esm并進(jìn)行最終的構(gòu)建,再次之前先安裝一個(gè)依賴shx,用于跨平臺(tái)執(zhí)行一些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官網(wǎng):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配置聲明模塊導(dǎo)出路徑

package.json中的exports字段用于告訴使用者引用此庫(kù)時(shí)從哪里尋找對(duì)應(yīng)的模塊文件.比如使用者可能通過(guò)esm模塊引用此庫(kù):

import{Foo}from'loaf';

constfoo=newFoo();

此時(shí)如果我們的package.json中沒(méi)有指定exports字段,那么模塊系統(tǒng)會(huì)去尋找node_modules/index.js,結(jié)果肯定是找不到的,因?yàn)槲覀冋嬲膃sm格式的輸出文件應(yīng)該是在node_modules/loaf/lib-esm中的

于是我們可以這樣來(lái)配置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和類(lèi)型聲明文件這一段中,我們通過(guò)tsc命令輸出了typescript了類(lèi)型聲明文件到dist/types目錄下,這個(gè)目錄下有兩個(gè).d.ts文件,分別是bar.d.ts和foo.d.ts,通常是希望這些聲明文件都在一個(gè)文件index.d.ts中的,如果他們分散開(kāi)了,以本庫(kù)為例,如果我要使用本庫(kù)中的Bar類(lèi),那么我可能需要這樣來(lái)導(dǎo)入:

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

我不覺(jué)得的這種導(dǎo)入方式是好的做法,理想的導(dǎo)入方式應(yīng)該像下面這樣:

import{Bar}from'loaf';

所以接下來(lái),還要引入微軟提供的api-extracto

溫馨提示

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

評(píng)論

0/150

提交評(píng)論