diff --git a/examples/browser-rollup/README.md b/examples/browser-rollup/README.md new file mode 100644 index 00000000..9ce6ecf7 --- /dev/null +++ b/examples/browser-rollup/README.md @@ -0,0 +1,110 @@ +

+ + IPFS in JavaScript logo + +

+ +

js-ipfs with rollup

+ +

+ Bundle js-ipfs with Rollup! +
+
+ +
+ Explore the docs + · + View Demo + · + Report Bug + · + Request Feature/Example +

+ +## Table of Contents + +- [Table of Contents](#table-of-contents) +- [About The Project](#about-the-project) +- [Getting Started](#getting-started) + - [Prerequisites](#prerequisites) + - [Installation and Running example](#installation-and-running-example) +- [Usage](#usage) +- [Documentation](#documentation) +- [Contributing](#contributing) +- [Want to hack on IPFS?](#want-to-hack-on-ipfs) + +## About The Project + +- Read the [docs](https://github.com/ipfs/js-ipfs/tree/master/docs) +- Look into other [examples](https://github.com/ipfs/js-ipfs/tree/master/examples) to learn how to spawn an IPFS node in Node.js and in the Browser +- Consult the [Core API docs](https://github.com/ipfs/js-ipfs/tree/master/docs/core-api) to see what you can do with an IPFS node +- Visit https://dweb-primer.ipfs.io to learn about IPFS and the concepts that underpin it +- Head over to https://proto.school to take interactive tutorials that cover core IPFS APIs +- Check out https://docs.ipfs.io for tips, how-tos and more +- See https://blog.ipfs.io for news and more +- Need help? Please ask 'How do I?' questions on https://discuss.ipfs.io + +## Getting Started + +### Prerequisites + +Make sure you have installed all of the following prerequisites on your development machine: + +- Git - [Download & Install Git](https://git-scm.com/downloads). OSX and Linux machines typically have this already installed. +- Node.js - [Download & Install Node.js](https://nodejs.org/en/download/) and the npm package manager. + +### Installation and Running example + +```console +> npm install +> npm start +``` + +Now open your browser at `http://localhost:8888` + +## Usage + +In this example, you will find a boilerplate you can use to guide yourself into bundling js-ipfs with [rollup](http://rollupjs.org/), so that you can use it in your own web app! + +You should see the following: + +![](./img/1.png) +![](./img/2.png) + +This example demonstrates the `Regular API`, top-level API for add, cat, get and ls Files on IPFS + +_For more examples, please refer to the [Documentation](#documentation)_ + +## Documentation + +- [Config](https://docs.ipfs.io/) +- [Core API](https://github.com/ipfs/js-ipfs/tree/master/docs/core-api) +- [Examples](https://github.com/ipfs/js-ipfs/tree/master/examples) +- [Development](https://github.com/ipfs/js-ipfs/blob/master/docs/DEVELOPMENT.md) + +## Contributing + +Contributions are what make the open source community such an amazing place to be learn, inspire, and create. Any contributions you make are **greatly appreciated**. + +1. Fork the IPFS Project +2. Create your Feature Branch (`git checkout -b feature/amazing-feature`) +3. Commit your Changes (`git commit -a -m 'feat: add some amazing feature'`) +4. Push to the Branch (`git push origin feature/amazing-feature`) +5. Open a Pull Request + +## Want to hack on IPFS? + +[![](https://cdn.rawgit.com/jbenet/contribute-ipfs-gif/master/img/contribute.gif)](https://github.com/ipfs/community/blob/master/CONTRIBUTING.md) + +The IPFS implementation in JavaScript needs your help! There are a few things you can do right now to help out: + +Read the [Code of Conduct](https://github.com/ipfs/community/blob/master/code-of-conduct.md) and [JavaScript Contributing Guidelines](https://github.com/ipfs/community/blob/master/CONTRIBUTING_JS.md). + +- **Check out existing issues** The [issue list](https://github.com/ipfs/js-ipfs/issues) has many that are marked as ['help wanted'](https://github.com/ipfs/js-ipfs/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3A%22help+wanted%22) or ['difficulty:easy'](https://github.com/ipfs/js-ipfs/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc+label%3Adifficulty%3Aeasy) which make great starting points for development, many of which can be tackled with no prior IPFS knowledge +- **Look at the [IPFS Roadmap](https://github.com/ipfs/roadmap)** This are the high priority items being worked on right now +- **Perform code reviews** More eyes will help + a. speed the project along + b. ensure quality, and + c. reduce possible future bugs. +- **Add tests**. There can never be enough tests. +- **Join the [Weekly Core Implementations Call](https://github.com/ipfs/team-mgmt/issues/992)** it's where everyone discusses what's going on with IPFS and what's next diff --git a/examples/browser-rollup/favicon.ico b/examples/browser-rollup/favicon.ico new file mode 100644 index 00000000..b2f1f968 Binary files /dev/null and b/examples/browser-rollup/favicon.ico differ diff --git a/examples/browser-rollup/img/1.png b/examples/browser-rollup/img/1.png new file mode 100644 index 00000000..524b0fc8 Binary files /dev/null and b/examples/browser-rollup/img/1.png differ diff --git a/examples/browser-rollup/img/2.png b/examples/browser-rollup/img/2.png new file mode 100644 index 00000000..003bf17a Binary files /dev/null and b/examples/browser-rollup/img/2.png differ diff --git a/examples/browser-rollup/index.html b/examples/browser-rollup/index.html new file mode 100644 index 00000000..8252e14d --- /dev/null +++ b/examples/browser-rollup/index.html @@ -0,0 +1,125 @@ + + + + + + + Bundle js-ipfs with rollup + + + + + + + + + +
+ + IPFS logo + +
+ +
+

Add data to IPFS from the browser

+ +
+ + + + + + + +
+ +

Output

+ +
+
+
+
+
+ + diff --git a/examples/browser-rollup/package.json b/examples/browser-rollup/package.json new file mode 100644 index 00000000..efd03667 --- /dev/null +++ b/examples/browser-rollup/package.json @@ -0,0 +1,32 @@ +{ + "name": "example-browser-browserify", + "description": "Bundle js-ipfs with Browserify", + "version": "1.0.0", + "main": "dist/index.html", + "private": true, + "scripts": { + "clean": "rimraf ./dist", + "build": "rollup -c", + "serve": "http-server dist -a 127.0.0.1 -p 8888", + "start": "npm run build && npm run serve", + "test:example": "npm run build && playwright test tests" + }, + "keywords": [], + "license": "MIT", + "devDependencies": { + "@playwright/test": "^1.12.3", + "@rollup/plugin-commonjs": "^19.0.2", + "@rollup/plugin-json": "^4.1.0", + "@rollup/plugin-node-resolve": "^13.0.4", + "http-server": "^0.12.3", + "playwright": "^1.12.3", + "rimraf": "^3.0.2", + "rollup": "^2.54.0", + "rollup-plugin-copy": "^3.4.0", + "rollup-plugin-polyfill-node": "^0.7.0", + "test-util-ipfs-example": "^1.0.2" + }, + "dependencies": { + "ipfs": "^0.55.4" + } +} diff --git a/examples/browser-rollup/public/ipfs-logo.svg b/examples/browser-rollup/public/ipfs-logo.svg new file mode 100644 index 00000000..f8633f62 --- /dev/null +++ b/examples/browser-rollup/public/ipfs-logo.svg @@ -0,0 +1 @@ + diff --git a/examples/browser-rollup/rollup.config.js b/examples/browser-rollup/rollup.config.js new file mode 100644 index 00000000..ac549fb6 --- /dev/null +++ b/examples/browser-rollup/rollup.config.js @@ -0,0 +1,32 @@ +import { nodeResolve } from '@rollup/plugin-node-resolve'; +import nodePolyfills from 'rollup-plugin-polyfill-node'; +import commonjs from '@rollup/plugin-commonjs'; +import json from '@rollup/plugin-json'; +import copy from 'rollup-plugin-copy' + +const config = { + input: 'src/index.js', + output: { + file: 'dist/index.js', + format: 'esm', + }, + context: 'globalThis', + plugins: [ + copy({ + targets: [ + { src: './index.html', dest: 'dist/' }, + { src: './favicon.ico', dest: 'dist/' }, + { src: 'public/**/*', dest: 'dist/public/' } + ] + }), + nodePolyfills(), + nodeResolve({ + browser: true, + preferBuiltins: false + }), + commonjs(), + json(), + ] +}; + +export default config; diff --git a/examples/browser-rollup/src/index.js b/examples/browser-rollup/src/index.js new file mode 100644 index 00000000..9adbed1d --- /dev/null +++ b/examples/browser-rollup/src/index.js @@ -0,0 +1,116 @@ +'use strict' + +import IPFS from 'ipfs' + +const App = () => { + let ipfs + + const DOM = { + output: () => document.getElementById('output'), + fileName: () => document.getElementById('file-name'), + fileContent: () => document.getElementById('file-content'), + addBtn: () => document.getElementById('add-submit'), + terminal: () => document.getElementById('terminal') + } + + const COLORS = { + active: '#357edd', + success: '#0cb892', + error: '#ea5037' + } + + const scrollToBottom = () => { + const terminal = DOM.terminal() + terminal.scroll({ top: terminal.scrollHeight, behavior: 'smooth' }) + } + + const showStatus = (text, bg, id = null) => { + let log = DOM.output() + + if (!log) { + const output = document.createElement('div') + output.id = 'output' + DOM.terminal().appendChild(output) + + log = DOM.output() + } + + const line = document.createElement('p') + line.innerText = text + line.style.color = bg + + if (id) { + line.id = id + } + + log.appendChild(line) + + scrollToBottom(log) + } + + const cat = async (cid) => { + const content = [] + + for await (const chunk of ipfs.cat(cid)) { + content.push(chunk) + } + + return content + } + + const store = async (name, content) => { + if (!ipfs) { + showStatus('Creating IPFS node...', COLORS.active) + + ipfs = await IPFS.create({ + repo: String(Math.random() + Date.now()), + init: { alogorithm: 'ed25519' } + }) + } + + const id = await ipfs.id() + showStatus(`Connecting to ${id.id}...`, COLORS.active, id.id) + + const fileToAdd = { + path: `${name}`, + content: content + } + + showStatus(`Adding file ${fileToAdd.path}...`, COLORS.active) + const file = await ipfs.add(fileToAdd) + + showStatus(`Added to ${file.cid}`, COLORS.success, file.cid) + + showStatus('Reading file...', COLORS.active) + + const text = await cat(file.cid) + + showStatus(`\u2514\u2500 ${file.path} ${text.toString()}`) + showStatus(`Preview: https://ipfs.io/ipfs/${file.cid}`, COLORS.success) + } + + // Event listeners + DOM.addBtn().onclick = async (e) => { + e.preventDefault() + let name = DOM.fileName().value + let content = DOM.fileContent().value + + try { + if (name == null || name.trim() === '') { + showStatus('Set default name', COLORS.active) + name = 'test.txt' + } + + if ((content == null || content.trim() === '')) { + showStatus('Set default content', COLORS.active) + content = 'Hello world!' + } + + await store(name, content) + } catch (err) { + showStatus(err.message, COLORS.error) + } + } +} + +App() diff --git a/examples/browser-rollup/tests/test.js b/examples/browser-rollup/tests/test.js new file mode 100644 index 00000000..e3339e90 --- /dev/null +++ b/examples/browser-rollup/tests/test.js @@ -0,0 +1,39 @@ +'use strict' + +const { test, expect } = require('@playwright/test'); +const { playwright } = require('test-util-ipfs-example'); + +// Setup +const play = test.extend({ + ...playwright.servers(), +}); + +play.describe('bundle ipfs with browserify:', () => { + // DOM + const nameInput = "#file-name" + const contentInput = "#file-content" + const submitBtn = "#add-submit" + const output = "#output" + + play.beforeEach(async ({servers, page}) => { + await page.goto(`http://localhost:${servers[0].port}/`); + }) + + play('should properly initialized a IPFS node and add/get a file', async ({ page }) => { + const fileName = 'test.txt' + const stringToUse = 'Hello world!' + + await page.fill(nameInput, fileName) + await page.fill(contentInput, stringToUse) + await page.click(submitBtn) + + await page.waitForSelector(`${output}:has-text("/QmQzCQn4puG4qu8PVysxZmscmQ5vT1ZXpqo7f58Uh9QfyY")`) + + const outputContent = await page.textContent(output) + + expect(outputContent).toContain("QmQzCQn4puG4qu8PVysxZmscmQ5vT1ZXpqo7f58Uh9QfyY"); + expect(outputContent).toContain("https://ipfs.io/ipfs/QmQzCQn4puG4qu8PVysxZmscmQ5vT1ZXpqo7f58Uh9QfyY"); + expect(outputContent).toContain(fileName); + expect(outputContent).toContain(stringToUse); + }); +});