Skip to content

Commit 0ed2b89

Browse files
committed
Chore: merged master and fixed conflicts
2 parents c5985e9 + dee8924 commit 0ed2b89

File tree

4 files changed

+123
-86
lines changed

4 files changed

+123
-86
lines changed

README.md

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,28 @@
44

55
A Nuxt module that enables nuxt routing for both the intended path and IPFS gateway URLs, which include a CID (hash) of the asset.
66

7-
Enabling this plugin for Nuxt in **static mode** will allow resources, including pages, to be accessible via two routes. For example:
7+
Enabling this plugin for Nuxt in **static mode** will allow resources, including pages, to be accessible via 3 different route structures:
88

99
- `foo.com/`
1010
- `gateway.ipfs.io/ipfs/Qma....AbFd/`
11+
- `ipfs.io/ipns/foo.com/`
1112

12-
Subsequently, resources and other pages use paths relative to those bases:
13-
- `foo.com/bar`
14-
- `gateway.ipfs.io/ipfs/Qma....AbFd/bar`
13+
Subsequently, resources and other pages automatically use paths relative to those bases:
14+
- `foo.com/bar.png`
15+
- `gateway.ipfs.io/ipfs/Qma....AbFd/bar.png`
16+
- `ipfs.io/ipns/foo.com/bar.png`
1517

1618
or
1719
- `foo.com/style.css`
1820
- `gateway.ipfs.io/ipfs/Qma....AbFd/style.css`
21+
- `ipfs.io/ipns/foo.com/style.css`
1922

2023
## Installation
2124

2225
_`npm` package coming soon. Manual installation required for now._
2326

2427
1. Download this repo, extract it and put the resulting folder into your `modules` directory in your Nuxt project
25-
2. Add `target: 'static'` to your `nuxt.config.js`
28+
2. Add `target: 'static'` and `router.base` to your `nuxt.config.js`
2629
3. Add the module folder name to the `modules` array in `nuxt.config.js`
2730

2831
**nuxt.config.js**
@@ -31,24 +34,23 @@ export default {
3134
target: 'static',
3235
modules: [
3336
'~/modules/nuxt-module-ipfs'
34-
]
37+
],
38+
router: {
39+
base: process.env.NODE_ENV === 'development' ? '/' : '/ipfs/hash/'
40+
}
3541
}
3642
```
3743

3844
## Usage
3945

4046
_Support for the `assets` directory potentially coming in the future_
4147

42-
All image assets must be placed in the `static` directory, _not_ the `assets` directory.
43-
44-
All links and image assets must be wrapped using the included `$relativity()` global method.
48+
All image assets must be placed in the `static` directory, _not_ the `assets` directory and must be wrapped using the included `$relativity()` (including a starting forward slash) global method as outlined below:
4549

4650
**component.vue**
4751
```vue
4852
<template>
49-
<nuxt-link :to="$relativity('/duck')">
50-
<img :src="$relativity('/images/duck.jpg')" />
51-
</nuxt-link>
53+
<img :src="$relativity('/images/duck.jpg')" />
5254
</template>
5355
```
5456

@@ -65,9 +67,7 @@ Additionally, it may be useful in the future to add a canonicalization option, t
6567
Since IPFS gateway URLs were an older (and by some standards _legacy_) implementation, this tag would typically be added to the IPFS Gateway URLs only.
6668

6769
## Roadmap
68-
- [ ] Update hook to clear `WARN` message: `render:routeContext(nuxt) is deprecated, Please use vue-renderer:ssr:context(context)`
6970
- [ ] Add checker for `target: static`
70-
- [ ] Add checker for `publicPath` and `router.base` (values _must not_ be set in `nuxt.config.js`)
7171
- [ ] Construct and inject `rel="canonical"` tag
72-
- [ ] Make the favicon path relative
72+
- [ ] Make the favicon path relative and working on all URL structures
7373
- [ ] Make `200.html` path relative

index.js

Lines changed: 94 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
// -----------------------------------------------------------------------------
99
// ///////////////////////////////////////////////////////////////////// General
1010
import Path from 'path'
11+
import { readFileSync, readdirSync, writeFileSync } from 'fs'
12+
import Klaw from 'klaw'
1113

1214
// ///////////////////////////////////////////////////////////////////// Plugins
1315
const MethodsPlugin = Path.resolve(__dirname, 'plugin.js')
@@ -31,70 +33,111 @@ const registerPlugins = (instance, next) => {
3133
if (next) { return next() }
3234
}
3335

34-
// ------------------------------------------------------------------ parseRoute
35-
const parseRoute = (route) => {
36-
const relativity = '../'.repeat(route.split('/').length - 1)
37-
return {
38-
// Make core nuxt files relative
39-
replaceSrc: route !== '/' ? `${relativity}_nuxt/` : '_nuxt/',
40-
// Make static directory files relative -- MUST run all component paths through $relativity method
41-
replaceStatic: route !== '/' ? `${relativity}` : ''
42-
}
36+
// ------------------------------------------------------------------------ seds
37+
const seds = (re, filepath, modifier) => {
38+
const original = readFileSync(filepath, 'utf8')
39+
const modified = original.replace(re, modifier)
40+
writeFileSync(filepath, modified)
41+
return modified
4342
}
4443

45-
// -------------------------------------------------------------------- addHooks
46-
const addHooks = (instance) => {
47-
let staticAssetsOpts
48-
let parsed
49-
50-
/*
51-
Grab the static asset path options to be applied in the render:routeContext
52-
hook (need the dir and the bundle version)
53-
*/
54-
55-
instance.nuxt.hook('generate:before', (generator, generateOptions) => {
56-
staticAssetsOpts = generateOptions.staticAssets
57-
})
58-
59-
/*
60-
Force the loading of all Javascript files
61-
*/
44+
// ------------------------------------------------------------------ relativize
45+
const relativize = (filepath) => {
46+
([,filepath] = filepath.split('/dist/'))
47+
let prefix = []
48+
let length = filepath.split('/').length - 1
49+
for (let i = 0; i < length; i++) {
50+
prefix.push('..')
51+
}
52+
prefix = prefix.join('/') + '/'
53+
return (prefix === '/' || prefix === '') ? './' : prefix
54+
}
6255

63-
instance.nuxt.hook('render:resourcesLoaded', (resources) => {
64-
resources.clientManifest.initial = resources.clientManifest.initial.concat(resources.clientManifest.async)
65-
initialScripts = resources.clientManifest.initial
66-
asyncScripts = resources.clientManifest.async
56+
// ------------------------------------------------------------------------ walk
57+
const walk = (dir, ext) => {
58+
return new Promise((next) => {
59+
const matches = []
60+
Klaw(dir)
61+
.on('data', ({ path }) => {
62+
if (path && !path.includes('node_modules') && path.endsWith(ext)) {
63+
matches.push(path)
64+
}
65+
})
66+
.on('end', () => {
67+
next(matches)
68+
})
6769
})
70+
}
6871

69-
/*
70-
This block gives us access to the generated javascript before it is
71-
serialized
72-
*/
73-
74-
instance.nuxt.hook('vue-renderer:ssr:context', (ctx) => {
75-
parsed = parseRoute(ctx.nuxt.routePath)
76-
// Apply url replacements to generated javascript before it is serialized
77-
ctx.staticAssetsBase = `${parsed.replaceSrc}${staticAssetsOpts.dir}/${staticAssetsOpts.version}`
78-
})
72+
// ------------------------------------------------------------ processHtmlFiles
73+
const processHtmlFiles = async (generateRoot) => {
74+
const htmlFiles = await walk(generateRoot, '.html')
75+
for (const htmlFile of htmlFiles) {
76+
const prefix = relativize(htmlFile)
77+
seds(/basePath:"\/ipfs\/hash\/"/gm, htmlFile, (
78+
'basePath:(ipfsMatch=window.location.pathname.match(/\\/ip[fn]s\\/[^/]+\\//), ipfsMatch?ipfsMatch[0]:\'/\')'
79+
))
80+
seds(/assetsPath:"\/_nuxt\/"/gm, htmlFile, (
81+
'assetsPath:(ipfsMatch=window.location.pathname.match(/\\/ip[fn]s\\/[^/]+\\//), ipfsMatch?ipfsMatch[0]:\'.\') + \'/_nuxt/\''
82+
))
83+
seds(/staticAssetsBase:"(\/_nuxt\/static\/)([^"]+)/gm, htmlFile, (_, start, end) => {
84+
return `staticAssetsBase:(ipfsMatch=window.location.pathname.match(/\\/ip[fn]s\\/[^/]+/),(ipfsMatch?ipfsMatch[0]:'.'))+"\u002F_nuxt\u002Fstatic\u002F${end}`
85+
})
86+
seds(/<base href="\/ipfs\/hash\/">/, htmlFile, true ? '' : (
87+
'<script>\n' +
88+
'base = document.createElement(\'base\')\n' +
89+
'base.href = (ipfsMatch=window.location.pathname.match(/\\/ip[fn]s\\/[^/]+/),(ipfsMatch?ipfsMatch[0]+\'/\':\'/\'))\n' +
90+
'document.getElementsByTagName(\'head\')[0].appendChild(base)\n' +
91+
'</script>'
92+
))
93+
seds(/"\/ipfs\/hash\//gms, htmlFile, `"${prefix}`)
94+
seds(/".\/images\//gms, htmlFile, `"${prefix}images/`)
95+
seds(/"\/favicon\//gms, htmlFile, `"${prefix}favicon/`)
96+
seds(/url\(\/ipfs\/hash\//gms, htmlFile, `url(${prefix}`)
97+
}
98+
}
7999

80-
/*
81-
This block gives us access to the generated HTML
82-
*/
100+
// -------------------------------------------------------------- processJsFiles
101+
const processJsFiles = async (generateRoot) => {
102+
const nuxtRoot = Path.join(generateRoot, '_nuxt')
103+
const jsFiles = await walk(nuxtRoot, '.js')
104+
for (const jsFile of jsFiles) {
105+
seds(/"\/ipfs\/hash\/_nuxt\/\"/, jsFile, (
106+
'(ipfsMatch=window.location.pathname.match(/\\/ip[fn]s\\/[^/]+\\//), ipfsMatch?ipfsMatch[0]+\'\/_nuxt\/\':\'\/_nuxt\/\')'
107+
))
108+
seds(/base: '\/ipfs\/hash\/'/gm, jsFile, (
109+
'base:(ipfsMatch=window.location.pathname.match(/\\/ip[fn]s\\/[^/]+\\//), ipfsMatch?ipfsMatch[0]:\'/\')'
110+
))
111+
seds(/(staticAssetsBase:"\\u002Fipfs\\u002Fhash\\u002F_nuxt\\u002Fstatic\\u002F)([^"]+)/gm, jsFile, (_, start, end) => {
112+
return `staticAssetsBase:(ipfsMatch=window.location.pathname.match(/\\/ip[fn]s\\/[^/]+/),(ipfsMatch?ipfsMatch[0]:''))+"/_nuxt\u002Fstatic\u002F${end}`
113+
})
114+
seds(/basePath:"\\u002Fipfs\\u002Fhash\\u002F"/gm, jsFile, (
115+
'basePath:(ipfsMatch=window.location.pathname.match(/\\/ip[fn]s\\/[^/]+\\//), ipfsMatch?ipfsMatch[0]:\'/\')'
116+
))
117+
seds(/assetsPath:"\\u002Fipfs\\u002Fhash\\u002F_nuxt\\u002F"/gm, jsFile, (
118+
'assetsPath:(ipfsMatch=window.location.pathname.match(/\\/ip[fn]s\\/[^/]+\\//), ipfsMatch?ipfsMatch[0]:\'.\') + \'/_nuxt/\''
119+
))
120+
seds(/return __webpack_require__\.p/gm, jsFile, (
121+
'return __webpack_require__.p.replace(\'./\', (ipfsMatch=window.location.pathname.match(/\\/ip[fn]s\\/[^/]+\\//), ipfsMatch?ipfsMatch[0]+\'/\':\'/\'))'
122+
))
123+
}
124+
}
83125

84-
instance.nuxt.hook('generate:page', (payload) => {
85-
parsed = parseRoute(payload.route)
86-
// Apply url replacements to generated HTML
87-
payload.html = payload.html
88-
.replace(/"\/_nuxt\//gi, `"${parsed.replaceSrc}`)
89-
.replace(/\(\/_nuxt\//gi, `(${parsed.replaceSrc}`)
90-
.replace(/\/relativity\//gi, parsed.replaceStatic)
126+
// -------------------------------------------------------------------- addHooks
127+
const addHooks = async (instance) => {
128+
instance.nuxt.hook('generate:done', async () => {
129+
const { dir: generateRoot } = instance.options.generate
130+
await processHtmlFiles(generateRoot)
131+
await processJsFiles(generateRoot)
91132
})
92133
}
93134

94135
// ////////////////////////////////////////////////////////////////// Initialize
95136
// -----------------------------------------------------------------------------
96137
function NuxtModuleIpfs () {
97-
console.log(`📦 [Module] NuxtModuleIpfs`)
138+
if (process.server) {
139+
console.log(`📦 [Module] NuxtModuleIpfs`)
140+
}
98141
registerPlugins(this, () => {
99142
if (process.env.NODE_ENV !== 'development') {
100143
addHooks(this)

package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "nuxt-module-ipfs",
3-
"version": "1.0.0-alpha.2",
4-
"description": "A module that enables Nuxt routing for both the intended path and IPFS gateway URLs, which include a hash",
3+
"version": "1.0.1-alpha.2",
4+
"description": "A Nuxt module that enables nuxt routing for both the intended path and IPFS gateway URLs, which include a CID (hash)",
55
"keywords": [
66
"Nuxt",
77
"NuxtJS",
@@ -12,8 +12,8 @@
1212
"bugs": "https://github.com/agency-undone/nuxt-module-ipfs/issues",
1313
"license": "Apache-2.0",
1414
"author": {
15-
"name": "Nauras Jabari",
16-
"url": "https://github.com/timelytree"
15+
"name": "Agency Undone",
16+
"email": "hello@agencyundone.com"
1717
},
1818
"contributors": [
1919
{

plugin.js

Lines changed: 10 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -4,30 +4,24 @@
44
*
55
*/
66

7-
console.log(`🔌 [Module | NuxtModuleIpfs] Methods`)
7+
if (process.server) {
8+
console.log(`🔌 [Module | NuxtModuleIpfs] Methods`)
9+
}
810

911
// /////////////////////////////////////////////////////////////////// Functions
1012
// -----------------------------------------------------------------------------
1113
// ------------------------------------------------------------------ relativity
12-
const Relativity = (path) => {
13-
if (process.env.NODE_ENV !== 'development') {
14-
const append = path.charAt(0) === '/' ? path.slice(1) : path;
15-
if (typeof window !== 'undefined') {
16-
const ipfsPathRegExp = /^(\/(?:ipfs|ipns)\/[^/]+)/;
17-
const ipfsPathPrefix = (window.location.pathname.match(ipfsPathRegExp) || [])[1] || '';
18-
if (ipfsPathPrefix) {
19-
return `${ipfsPathPrefix}${path}/`;
20-
} else {
21-
return path;
22-
}
23-
}
24-
return `/relativity/${append}`;
14+
const Relativity = function (path) {
15+
if (process.client) {
16+
if (!path) { return '' }
17+
const ipfsMatch = window.location.pathname.match(/^(\/(?:ipfs|ipns)\/[^/]+)/)
18+
return ipfsMatch ? ipfsMatch[0] + path : path
2519
}
26-
return path;
20+
return path
2721
}
2822

2923
// ///////////////////////////////////////////////////////////// Export & Inject
3024
// -----------------------------------------------------------------------------
31-
export default ({}, inject) => {
25+
export default (ctx, inject) => {
3226
inject('relativity', Relativity)
3327
}

0 commit comments

Comments
 (0)