使用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

提交评论