Rollup构建
Rollup打包后的体积较小,可以做一些小框架、小项目
安装依赖
全局安装rollup
安装TypeScript
1
| npm install typescript -D
|
安装TypeScript 转换器
1
| npm install rollup-plugin-typescript2 -D
|
安装代码压缩插件
1
| npm install rollup-plugin-terser -D
|
安装rollupweb服务
1
| npm install rollup-plugin-serve -D
|
安装热更新
1
| npm install rollup-plugin-livereload -D
|
引入外部依赖
1
| npm install rollup-plugin-node-resolve -D
|
安装配置环境变量用来区分本地和生产
1
| npm install cross-env -D
|
替换环境变量给浏览器使用
1
| npm install rollup-plugin-replace -D
|
配置文件
rollup.config.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| import ts from "rollup-plugin-typescript2" import serve from "rollup-plugin-serve" import livereload from "rollup-plugin-livereload" import { terser } from "rollup-plugin-terser" import replace from "rollup-plugin-replace"
import path from "path" import { fileURLToPath } from "url" const metaUrl = fileURLToPath(import.meta.url) const dirName = path.dirname(metaUrl)
const isDev = ()=> { return process.env.NODE_ENV === "development" }
export default { input: "./src/index.ts", output: { file: path.resolve(dirName,"./lib/index.js"), format: "umd", sourcemap: true },
plugins:[ ts(), isDev() && livereload(), terser(), replace({ "process.env.NODE_ENV": JSON.stringify(process.env.NODE_ENV) }), isDev() && serve({ open: true, port: 11451, openPage: "/public/index.html" }) ] }
|
package.json:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| { "name": "test2", "version": "1.0.0", "description": "", "main": "index.js", "type": "module", "scripts": { "test": "echo \"Error: no test specified\" && exit 1", "dev": "cross-env NODE_ENV=development rollup -c -w", "build":"cross-env NODE_ENV=produaction rollup -c" }, "keywords": [], "author": "", "license": "ISC", "devDependencies": { "cross-env": "^7.0.3", "rollup-plugin-livereload": "^2.0.5", "rollup-plugin-node-resolve": "^5.2.0", "rollup-plugin-replace": "^2.2.0", "rollup-plugin-serve": "^1.1.0", "rollup-plugin-terser": "^7.0.2", "rollup-plugin-typescript2": "^0.31.1", "typescript": "^4.5.5" } }
|
设置tsconfig.json:
Webpack构建
安装依赖
安装webpack
webpack4以上需要
1
| npm install webpack-cli -D
|
编译TS
1
| npm install ts-loader -D
|
TS环境
1
| npm install typescript -D
|
热更新服务
1
| npm install webpack-dev-server -D
|
HTML模板
1
| npm install html-webpack-plugin -D
|
配置文件
webpack.config.js:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33
| const path = require("path") const HtmlWebpackPlugin = require("html-webpack-plugin")
module.exports = { entry: "./src/index.ts", output: { path: path.resolve(__dirname,"./dist"), filename: "index.js" }, module: { rules: [ { test: /\.ts$/, use:"ts-loader" } ] }, devServer: { port: 11451, proxy: {
} }, resolve: { extensions: [".js",".ts"] }, plugins: [ new HtmlWebpackPlugin({ template: "./public/index.html" }) ], mode: "development" }
|
esbuild+SWC构建
esbuild
esbuild使用go语言编写,多线程执行,性能是js的好几十倍,所以很快
esbuild的优点:
- 无需缓存即可实现基础打包
- 支持ES6跟CommonJS 模块
- 支持ES6 Tree Shaking
- 体积小
- 插件化
- 其他
- 内置支持编译jsx
Vite的开发模式基于esbuild
SWC
SWC是用Rust写的,所实现的功能跟babel一样(es6语法转es5),但是速度比babel更快
安装依赖
1
| npm install @swc/core esbuild @swc/helpers
|
如果项目需要支持JSX或TSX,安装@swc/helpers,否则无需安装
配置文件
设置tsconfig.json:
1 2 3
| "target": "ESNext", "module": "ESNext", "moduleResolution": "node"
|
设置package.json:
config.ts:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| import esbuild from "esbuild" import swc from "@swc/core" import fs from "node:fs"
await esbuild.build({ entryPoints: ["index.ts"], treeShaking: true, bundle: true, loader: { ".js": "js", ".ts": "ts", ".jsx": "jsx", ".tsx": "tsx" }, plugins: [ { name: "swc-loader", setup(build) { build.onLoad({filter:/\.(js|ts|jsx|tsx)$/},(args)=>{ const content = fs.readFileSync(args.path, "utf-8") const {code, map} = swc.transformSync(content, { filename: args.path }) return { contents: code } }) } } ], outdir: "dist" , })
|
打包命令:
实例
打包工具配置(rollup.config.js):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| import ts from "rollup-plugin-typescript2" import path from "path" import { fileURLToPath } from "url" const metaUrl = fileURLToPath(import.meta.url) const dirName = path.dirname(metaUrl)
export default { input: "./src/index.ts", output: { file: path.resolve(dirName,"./dist/index.js"), }, plugins:[ ts(), ] }
|
LocalStorage过期实例
该库提供将LocalStorage像Cookie一样可限时存储的功能
定义字符串枚举(/src/enum/index.ts):
1 2 3 4
| export enum Dictionaries { permanent = "permanent", expire = "__expire__" }
|
定义类型(/src/type/index.ts):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import { Dictionaries } from "../enum"
export type Key = string export type Expire = Dictionaries.permanent | number
export interface Data<T> { value:T, [Dictionaries.expire]:Expire } export interface Result<T> { message:string, value:T|null } export interface StorageCls { get:<T>(key:Key)=>Result<T> set:<T>(key:Key,value:T,expire:Expire)=>void remove:(key:Key)=>void clear:()=>void }
|
核心代码(/src/index.ts):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| import { StorageCls, Key, Expire, Data, Result } from "./type" import { Dictionaries } from "./enum"
export class Storage implements StorageCls { set<T>(key:Key, value:T, expire:Expire=Dictionaries.permanent) { const data = { value, [Dictionaries.expire]:expire } localStorage.setItem(key,JSON.stringify(data)) }
get<T>(key:Key):Result<T> { const value = localStorage.getItem(key) if(value) { const data:Data<T> = JSON.parse(value) const now = new Date().getTime() if(typeof data[Dictionaries.expire] === "number" && data[Dictionaries.expire] < now) { this.remove(key) return { message: `${key}已过期`, value: null } } else { return { message: "取值成功", value: data.value } } } else { return { message: `${key}无效`, value: null } } }
remove(key:Key) { localStorage.removeItem(key) }
clear() { localStorage.clear() } }
|
发布订阅模式实例
定义类型(/src/type/index.ts):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| export interface Event { on:(name:string,fn:Function)=>void emit:(name:string,...args:any[])=>void off:(name:string,fu:Function)=>void once:(name:string,fn:Function)=>void }
export interface List { [key:string]:Function[] }
|
核心代码(/src/index.ts):
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| import { Event, List } from "./type"
class Dispatch implements Event { list:List constructor() { this.list = {} } on(name:string,fn:Function) { const cbs = this.list[name] || [] cbs.push(fn) this.list[name] = cbs } emit(name:string,...args:any[]) { const cbs = this.list[name] if(cbs) { cbs.forEach(cb=> { cb.apply(this,args) }) } else { console.error(`没有注册${name}事件`) } } off(name:string,fn:Function) { const cbs = this.list[name] if(cbs && fn) { const index = cbs.findIndex(fns=>fns===fn) cbs.splice(index,1) } else { console.error(`没有注册${name}事件或函数有误`) } } once(name:string,fn:Function) { const temp = (...args:any[])=> { fn.apply(this,args) this.off(name,temp) } this.on(name,temp) } }
|