Skip to content

Instantly share code, notes, and snippets.

@Xananax
Created September 1, 2021 17:31
Show Gist options
  • Save Xananax/5dca3a1dd7070e4fdebe2927e4aeb55b to your computer and use it in GitHub Desktop.
Save Xananax/5dca3a1dd7070e4fdebe2927e4aeb55b to your computer and use it in GitHub Desktop.
MDSvex Global Components
import remarkAbbr from 'remark-abbr'
import rehypeSlug from 'rehype-slug'
import rehypeAutolinkHeadings from 'rehype-autolink-headings'
import md from 'mdsvex'
export const extensions = ['.svelte.md', '.md', '.svx']
export const mdsvex = md.mdsvex({
extensions,
smartypants: {
dashes: 'oldschool'
},
remarkPlugins: [remarkAbbr],
rehypePlugins: [
rehypeSlug,
[
rehypeAutolinkHeadings,
{
behavior: 'wrap'
}
]
]
})
import { join, basename, extname } from 'path'
export const defaults = {
extensions: ['.svelte.md', '.md', '.svx'],
dir: `$lib`,
list: []
}
/**
* Injects global imports in all your mdsvex files
* Specify:
* - the root dir (defaults to `src/lib`)
* - the array list of components (with extension), like `['Component.svelte']`
* - the valid extensions list as an array (defaults to `['.svelte.md', '.md', '.svx']`)
*
* If you want the component name to be different from the file name, you can specify an array
* of arrays: `['Component.svelte', ['Another', 'AnotherComp.svelte'], 'ThirdComp.svelte']`
*
* @param {Object} options options described above
* @returns a preprocessor suitable to plug into the `preprocess` key of the svelte config
*/
export const mdsvexGlobalComponents = (options = {}) => {
const { extensions, dir, list } = { ...defaults, ...options }
const extensionsRegex = new RegExp('(' + extensions.join('|').replace(/\./g, '\\.') + ')$', 'i')
if (!list || !list.length || !Array.isArray(list)) {
throw new Error(`"list" option must be an array and contain at least one element`)
}
const imports = list
.map((entry) => {
let name = ''
if (Array.isArray(entry)) {
name = entry[0]
entry = entry[1]
}
const ext = extname(entry)
const path = join(dir, entry)
name = name || basename(entry, ext)
return `\nimport ${name} from "${path}"`
})
.join('\n')
const preprocessor = {
script(thing) {
const { content, filename, attributes, markup } = thing
if (!filename.match(extensionsRegex)) {
return { code: content }
}
const hasModuleContext = /^<script context="module">/.test(markup)
const isModulePass = attributes?.context === 'module'
const isValidPass = (hasModuleContext && isModulePass) || !hasModuleContext
if (!isValidPass) {
return { code: content }
}
return { code: `${imports}\n${content}` }
}
}
return preprocessor
}
import preprocess from 'svelte-preprocess'
import { mdsvex, extensions } from './svelte-kit/mdsvex.config.js'
import { mdsvexGlobalComponents } from './svelte-kit/mdsvexGlobalComponents.js'
const globalComponents = mdsvexGlobalComponents({
dir: `$lib/components`,
list: ['Note.svelte', 'Youtube.svelte', ['Ref', 'RefLink.svelte']],
extensions
})
/** @type {import('@sveltejs/kit').Config} */
const config = {
extensions: ['.svelte', ...extensions],
preprocess: [preprocess(), globalComponents, mdsvex],
kit: {
target: '#svelte',
}
}
export default config
@artemkovalyov
Copy link

Great stuff, made it work with ease. Thanks for sharing.

@rchrdnsh
Copy link

rchrdnsh commented Apr 28, 2023

hmmmm…is there a way to specify a different path for each component? Using only ‘$lib/components’ won’t work for me, as I have many different components in many different folders and sub folders.

@bennymi
Copy link

bennymi commented Apr 29, 2023

@rchrdnsh I haven't tried this yet, but I'm assuming you could update this part to include a third element in the list which is the path to the component:

const imports = list
    .map((entry) => {
      let name = ''
      if (Array.isArray(entry)) {
        name = entry[0]
        entry = entry[1]
        component_path = entry.length === 3 ? entry[2] : ''
      }
      const ext = extname(entry)
      const path = join(component_path ?? dir, entry)
      name = name || basename(entry, ext)
      return `\nimport ${name} from "${path}"`
    })
    .join('\n')

And then maybe doing something like this:

 mdsvexGlobalComponents({
      dir: `$lib/components`,
      list: [["Test", "test.svelte", "./src/mdsvex-components"]],
}),

@Xananax
Copy link
Author

Xananax commented Apr 29, 2023

It's my code but it's old and I'm not using this anymore, so I'm not sure; but it seems to me like you can just use paths:

const globalComponents = mdsvexGlobalComponents({
  ...
  list: ['path/to/Note.svelte', 'otherpath/to/Youtube.svelte', ['Ref', 'thirdpath/to/RefLink.svelte']],
 ...
})

@rchrdnsh
Copy link

rchrdnsh commented May 1, 2023

hmmm...I'll give that a try...not using anymore, though?

Is this problem still an issue for you? Got something better?

@Xananax
Copy link
Author

Xananax commented May 1, 2023

"Better" depends on specifics, there isn't a universal grading for frameworks, so I can't speak to that.

We never actually used this. I was only reviewing Svelte as part of R&D for our company, and we decided the changing JS semantics made it too troublesome to get new people onboarded. The compiler aspect is lovely, but it also means you have trouble understanding what happens to your code (Harris advocates the opposite position in his latest talk; I respectfully disagree). The build steps are also too magical, which made it difficult for us to hook into for our custom needs.

Despite personally preferring Svelte's approach, I decided on Next, which is its own bundle of issues but works better for our use case.

@rchrdnsh
Copy link

rchrdnsh commented May 2, 2023

oh, no, I meant better for this particular problem of auto importing svelte components into mdsvex files 🤣

I am personally all in on svelte, as I did not like react, as I came from html and css and design first, so svelte feels good to me, but I feel you, esp. if a team is js centric and all :-)

But in any case, hopefully this can work for me, as I am importing at least 50 or so svelte components into every single markdown file, which is no fun to update when I add or change one! 🥵

@Xananax
Copy link
Author

Xananax commented May 2, 2023

Oh sorry, I was not very focused 😅

In retrospect your question was evident. To answer it: no, I don't know of anything better, but this should work. If it doesn't, share your repo and I'll probably be able to help!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment