を構築するミニGoogleドライブクローンを迅速に
52078 ワード
TL;DR you can find code at https://github.com/sergeyt/multidisk
私は比較的迅速にどのように比較的迅速に小さなGoogleのドライブのアプリやその種類を構築する方法を示します.私は、「Googleドライブ」が少し挑発的に聞こえるかもしれないということを知っています😄. また、私を信じていないが、私はいくつかの朝以内にアプリを行ってきた😄). 以下は、私がしたことと方法についての若干の詳細です.
ハイレベルアイデア
アイデアは簡単です.すべてのドライブに統一UIを作りたいです.簡素化のために出発点としてプラットフォームを少しだけ選んだ.
Uploadcare - ニースとシンプルなAPIで全く新しいものと無料プランを持っている
Dropbox - 何の紹介も必要ない
今までやったこと
機能の面では、アプリケーションは、次の機能が含まれます
ツーリング
アプリケーションを構築するには、次のツールを選択しました
TypeScript - 私は最近、どんなプロジェクトの開始から型を好む.この理由は別々に論じられる😄. 多分私が最初にプログラミングを始めたので
Uploadcare - 私のための新しいものは、一緒に新しい何かを学ぶことができます
Next.js - どんな導入も必要でない
Material UI - 良い反応のフレームワークのコンポーネントの多く.多分後で私は使用するアプリをリファクタリングしますChakra UI 私にも期待しているから
どうやってやったの
私の手順は
プロジェクトブートストラップ
によるとthis Next.js doc それはちょうど実行しているように簡単です
npx create-next-app
あなたのシェルのコマンドとあなたは文字通り行われます😄ドライブインタフェース
このポストをいくつかのコードでポンピングする時です😄. 私は、どんなドライブとそのオブジェクトも抽象化するために、以下のインターフェースを思いつきました.これらの抽象化は、異なるストレージプロバイダを統一するために必要です.
export type ItemType = "file" | "folder";
export interface Item {
type: ItemType;
id: string;
name: string;
path: string;
driveId: string;
}
export interface File extends Item {
size: number;
createdAt: Date;
url?: string;
download?: () => Promise<any>;
}
export interface Drive {
options: any;
provider: string;
getItems(folderId?: string): Promise<Item[]>;
deleteFile(fileId: string): Promise<void>;
deleteFolder(folderId: string): Promise<void>;
}
アップロードの実装
アップロードのAPIドキュメントはhttps://uploadcare.com/api-refs/rest-api/v0.5.0/ .
私たちはちょうどaxios HTTPリクエストを作成するために、私は私のニーズのための任意のタイプのクライアントを見つけませんでした.私は、UploadCare APIクライアントのために小さなNPMパッケージをして満足です.私は知っているthis one , しかし、現在アップロードしてファイルをダウンロードし、それはアップロードAPIのすべての機能をカバーしていません.たぶんGitTubでそれを要求する必要があるかもしれない😄
import axios from "axios";
import { Drive, File, Item } from "../types";
import { checkResponseOK } from "./utils";
type Options = {
type: string;
id: string;
name: string;
publicKey: string;
secretKey: string;
};
export default class UploadcareDrive implements Drive {
private _options: Options;
constructor(options: Options) {
this._options = options;
}
get options(): Options {
return this._options;
}
get provider() {
return this.options.type;
}
get id() {
return this.options.id;
}
get name() {
return this.options.name;
}
axios() {
return axios.create({
headers: {
Accept: "application/vnd.uploadcare-v0.5+json",
Authorization: `Uploadcare.Simple ${this.options.publicKey}:${this.options.secretKey}`,
},
});
}
async getItems(folderId?: string): Promise<Item[]> {
const resp = await this.axios().get("https://api.uploadcare.com/files/");
checkResponseOK(resp);
return resp.data.results.map(
(f) =>
({
type: "file",
driveId: this.id,
id: f.uuid,
name: f.original_filename,
createdAt: new Date(f.datetime_uploaded),
url: f.original_file_url,
size: f.size,
} as File)
);
}
async deleteFile(fileId: string): Promise<void> {
const resp = await this.axios().delete(
`https://api.uploadcare.com/files/${fileId}/`
);
checkResponseOK(resp);
}
deleteFolder(folderId: string): Promise<void> {
return Promise.resolve(undefined);
}
}
Dropboxドライブの実装
Dropboxがa wonderful docs ともinteractive playground APIエクスプローラーと呼ばれます.私は、DropboxDriveのバージョンを実装しました.そして、それはさわやかなトークン能力なしで短命なトークンを使用しました.すみませんが、今度は今度は改定する時間を見つけます.
現在のバージョンのコード:
import axios from "axios";
import trimStart from "lodash/trimStart";
import { Drive, Item, File } from "../types";
import { checkResponseOK, downloadBlob, trimPrefix } from "./utils";
type Options = {
type: string;
id: string;
name: string;
accessToken: string;
};
export default class DropboxDrive implements Drive {
private _options: Options;
constructor(options: Options) {
this._options = options;
}
get provider() {
return "dropbox";
}
get id() {
return this.options.id;
}
get name() {
return this.options.name;
}
get options() {
return this._options;
}
async getItems(folderId: string = ""): Promise<Item[]> {
if (!folderId.startsWith("/")) {
folderId = "/" + folderId;
}
const resp = await this.axios().post(
"https://api.dropboxapi.com/2/files/list_folder",
{
path: folderId === "/" ? "" : folderId,
}
);
checkResponseOK(resp);
return resp.data.entries.map((entry) => {
if (entry[".tag"] === "file") {
return {
type: "file",
id: trimPrefix(entry.id, "id:"),
name: entry.name,
path: entry.path_display,
createdAt: new Date(entry.server_modified),
driveId: this.id,
size: entry.size,
download: async () => {
const resp = await this.axios().post(
"https://content.dropboxapi.com/2/files/download",
undefined,
{
headers: {
"Dropbox-API-Arg": JSON.stringify({ path: entry.id }),
},
responseType: "blob",
}
);
downloadBlob(resp.data, entry.name);
},
} as File;
}
return {
type: "folder",
id: trimStart(entry.path_display, "/"),
name: entry.name,
path: entry.path_display,
driveId: this.id,
} as Item;
});
}
async deleteFile(fileId: string): Promise<void> {
const resp = this.axios().post(
"https://api.dropboxapi.com/2/file_requests/delete",
{
ids: [fileId],
}
);
checkResponseOK(resp);
}
deleteFolder(folderId: string): Promise<void> {
return Promise.resolve(undefined);
}
axios() {
return axios.create({
headers: {
Authorization: `Bearer ${this.options.accessToken}`,
"Content-Type": "application/json",
},
});
}
}
アプリケーション
アプリのMVPバージョンわずか数ページといくつかのダイアログがあります
のホームページ
私たちはSWR 次の推奨データを取得します.JSフォークス.ホームは簡単な実装です.ホームページの完全なスクリプトはこちら
import isEmpty from "lodash/isEmpty";
import useSWR from "swr";
import { getDrives } from "../core/store";
import Loader from "../components/Loader";
import Placeholder from "../components/Placeholder";
import DriveList from "../components/DriveList";
export default function Home() {
const { data: drives } = useSWR("/drives", getDrives);
if (!drives) {
return <Loader />;
}
if (isEmpty(drives)) {
return (
<Placeholder>
You don't any drives, but you can create one clicking on ADD DRIVE
button
</Placeholder>
);
}
return <DriveList drives={drives} />;
}
Driveistコンポーネントが次のようにコーディングされている場合import Link from "next/link";
import ListItem from "@material-ui/core/ListItem";
import ListItemAvatar from "@material-ui/core/ListItemAvatar";
import Avatar from "@material-ui/core/Avatar";
import DriveIcon from "@material-ui/icons/Work";
import ListItemText from "@material-ui/core/ListItemText";
import ListItemSecondaryAction from "@material-ui/core/ListItemSecondaryAction";
import List from "@material-ui/core/List";
import { Drive } from "../types";
import DriveMenu from "./DriveMenu";
export default function DriveList({ drives }: { drives: Drive[] }) {
const items = drives.map((d, k) => (
<Link href={`/drive/${d.id}`} key={k}>
<ListItem style={{ cursor: "pointer" }}>
<ListItemAvatar>
<Avatar>
<DriveIcon />
</Avatar>
</ListItemAvatar>
<ListItemText primary={d.name} secondary={d.driveType} />
<ListItemSecondaryAction>
<DriveMenu driveId={d.id} />
</ListItemSecondaryAction>
</ListItem>
</Link>
));
return <List>{items}</List>;
}
ドライブビューページ
また以下のように簡単です.
import { useRouter } from "next/router";
import useSWR from "swr";
import { Box } from "@material-ui/core";
import { Widget } from "@uploadcare/react-widget";
import { getDrive } from "../../core/store";
import Loader from "../../components/Loader";
import ItemList from "../../components/ItemList";
export default function DriveView() {
const router = useRouter();
const { id } = router.query;
const { data, revalidate } = useSWR(`/drive/${id}`, async () => {
const drive = await getDrive(String(id));
const items = await drive.getItems();
return { drive, items };
});
if (!data) {
return <Loader />;
}
return (
<>
<Box m={2} mb={2}>
<label>Upload a file: </label>
<Widget
publicKey={data.drive.options.publicKey}
onChange={revalidate}
/>
</Box>
<ItemList data={data.items} />
</>
);
}
ここでitemlistは以下のように符号化されます:import isEmpty from "lodash/isEmpty";
import List from "@material-ui/core/List";
import { Item, File, Folder } from "../types";
import FileItem from "./FileItem";
import FolderItem from "./FolderItem";
import Placeholder from "./Placeholder";
export default function ItemList({ data }: { data: Item[] }) {
if (isEmpty(data)) {
return (
<Placeholder>
This drive is empty, but you can fill it out with something :)
</Placeholder>
);
}
const items = data.map((item, k) => {
switch (item.type) {
case "file":
return <FileItem key={k} item={item as File} />;
case "folder":
return <FolderItem key={k} item={item as Folder} />;
default:
return null;
}
});
return <List>{items}</List>;
}
あなたがアップロードファイルがちょうど使用されて実装されることに気づいたかもしれないようにUploadcare ウィジェット-素敵なもう一つの大きな時間の節約.どうやってダイアログをやったの?
あなたは本当にダイアログのコードを読みたいですか?それは退屈であるべきです.そして、多分、それはこのブログ柱のために十分でなければなりません😄
とにかく、あなたは行くことができますthe github repo いくつかの楽しい情報の追加ビットを消費している😄
次の手順
次の時間は、おそらく次のようなアプリケーションでより多くの機能を追加しようとします.
リンクoriginal post
Reference
この問題について(を構築するミニGoogleドライブクローンを迅速に), 我々は、より多くの情報をここで見つけました https://dev.to/sergeyt/lets-build-mini-google-drive-clone-quickly-29m6テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol