Coder Social home page Coder Social logo

xm's Introduction

₪ xm - extensible HTML

xm is a tiny compiler for HTML that adds

  • <import> tag to inline external HTML files
  • <slot> and <fill> tags to define slots and fill them with content
  • <markdown> tag to portal into Markdown

screenshot of an html template with slots

screenshot of an html page that imports the previous example and fills the slots

xm CLI comes with a dev mode that compiles and serves built HTML.

Furthermore xm is built on top of posthtml-cli and therefore it is extensible.

Are you using xm? Share your site's URL here.

Install

npm i -g xm

Usage

Usage: xm <command> [options]

Commands:

  dev     Compiles HTML files on change and serves the root folder
  build   Compiles the HTML files once
  help    Displays help

Options:

  --root       Folder to compile (default ./)
  --output     Output (destination) folder. This is necessary only when using xm build
  --htmlOnly   Compile and copy only the built HTML files

<import> element

Allows to inline (import) HTML files into the current one.

<import src="file.html" />

Paths are relative.

<!-- src/folder/index.html -->

<import src="file.html" />
<!-- file.html -> src/folder/file.html -->

You can prefix paths with / to make them absolute i.e. relative to the --root value.

$ xm build --root ./src
# <import src="file.html" />
# -> ./src/file.html

Importing markdown files

xm supports importing .md (markdown) files too. When importing such files the front matter declarations are converted to fill elements.

<style>
  /* theme */
</style>
<import src="README.md" />

💡 This feature can be used to generate styled docs sites for your open source project!

If you create a reusable theme for README-like files we encourage you to use the following naming convention:

xm-theme-<theme-name>

Share your site or theme URL here.

<slot> and <fill> elements

HTML files can define slot elements with an attribute name. slots can be filled when importing HTML files using the fill tag.

<!-- base.html -->

<!DOCTYPE html>
<title><slot name="title"></slot></title>
<main>
  <slot name="main"></slot>
</main>

<!-- about.html -->

<import src="base.html">
  <fill name="title">About</fill>
  <fill name="main">
    <h1>About</h1>
    <p>welcome</p>
  </fill>
</import>
<footer>Unique to this page</footer>

<!-- about.html (compiled with xm) -->

<!DOCTYPE html>
<title>About</title>
<main>
  <h1>About</h1>
  <p>welcome</p>
</main>
<footer>Unique to this page</footer>

You can also define a special unnamed slot that will be filled with the import children that are not fill tags:

<!-- base.html -->

<slot></slot>
<footer><slot name="footer"></slot></footer>

<!-- about.html -->

<import src="base.html">
  <fill name="footer">good bye</fill>
  hello
  <p>friend</p>
</import>

<!-- about.html (compiled with xm) -->

hello
<p>friend</p>
<footer>good bye</footer>

Credits

  • Ivan Demidov for helping me out with PRs and PostHTML
  • askucher for transferring ownership of the xm package

xm's People

Contributors

deimos avatar giuseppeg avatar pacocoursey avatar pengwynn avatar scrum avatar suchipi avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

xm's Issues

`xm dev` throws "fs.rmSync is not a function"

When running xm dev when there's an .xm cache folder present, I get:

(...)/xm/index.js:86
  fs.rmSync(outDir, { recursive: true, force: true });
     ^

TypeError: fs.rmSync is not a function

Could have been introduced by the change on index.js:86 here v1.0.5...v1.0.6

Steps to reproduce:

  1. Create a basic project, like one from the examples.
  2. Run xm dev
  3. Visit your project once and make sure you now see a .xm folder in the root of your project.
  4. Stop the xm dev process.
  5. Run it again

When using custom root, dev throws error because `.xm` folder doesn't exist

Using xm 1.0.3, when running:

xm dev --root ./src

I get the following error:

> xm dev --root ./src


  ₪ xm  extensible static HTML

fs.js:114
    throw err;
    ^

Error: ENOENT: no such file or directory, rmdir 'src/.xm'
    at Object.rmdirSync (fs.js:684:3)
    at Object.<anonymous> (/Users/lily/[redacted]/node_modules/xm/index.js:78:4)
    at Module._compile (internal/modules/cjs/loader.js:778:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
    at Module.load (internal/modules/cjs/loader.js:653:32)
    at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
    at Function.Module._load (internal/modules/cjs/loader.js:585:3)
    at Function.Module.runMain (internal/modules/cjs/loader.js:831:12)
    at startup (internal/bootstrap/node.js:283:19)
    at bootstrapNodeJSCore (internal/bootstrap/node.js:623:3)

Idea: Serve markdown files as html pages

If I have a folder full of markdown files, it would be cool to support a import: base.html property in its frontmatter attributes. Ideally this would treat the markdown file such as:

<import src="base.html">
    <any fills other than the import attribute/>
    <markdown>the markdown</markdown>
</import>

Use as a gulp plugin

Would you have any guidance on how to use xm within gulp? My first instinct would be to use the gulp-posthtml plugin and somehow inject xm that gulp stream, but I'm not sure if that's even possible, seeing that xm is more of it's own cli tool built on top of posthtml?

Refresh page on changes

We should automatically refresh the page when making changes otherwise we'd need to do a manual refresh all the time.

Sites using xm

If you use xm you can share your site's URL here and perhaps a link to the GitHub repo.

Use as devDependency

I ran into an issue using xm as a devDependency. When running npx xm dev while it's intalled, I get the following when visiting the website:

  ₪  Serving / ...
obfuscated/node_modules/xm/utils.js:62
    onMsg(child.stdout.toString());
                       ^

TypeError: Cannot read property 'toString' of null
    at spawn (obfuscated/node_modules/xm/utils.js:62:24)
    at Server.<anonymous> (obfuscated/node_modules/xm/index.js:145:9)
    at Server.emit (events.js:310:20)
    at parserOnIncoming (_http_server.js:786:12)
    at HTTPParser.parserOnHeadersComplete (_http_common.js:119:17)

It works fine of course if I don't have xm installed locally.

Steps to reproduce:

  1. On a fresh project npm install --save-dev xm
  2. Run npx xm dev
  3. Visit the address where the website is served.

RFC: Support slot attributes and data cascade

⚠️ this feature is related to the Collections proposal and probably should be implemented before #17.

slot attributes

Currently xm support only element slots:

<slot name="title"></slot>

We should add support for slot attributes:

<a slot:href="https://{domain}/contact">contact me</a>

These will be filled with fill elements eg:

<fill name="domain">acme.com</fill>

spec

Any attribute can be slotted if prefixed with slot:. Within the value for the attribute there can be multiple expressions delimited with { and }. The expression name matches a fill name, and xm replaces the expression with the fill value.

Data Cascade

xm should allow to define multiple sources for data, including a global data object that is provided via config file.

We need to rework the main plugin to merge the data correctly using a Data Cascade mechanism similar to the 11ty's one. Check out https://www.11ty.dev/docs/data-cascade/

Additionally we need to provide a global xm:permalink fill value that contains the absolute path for the file so that people can use it to reference to the current page (eg. when creating sharing links). The xm: namespace will be reserved for xm fill values.

RFC: Collections

⚠️ this feature is strictly related to the data cascade proposal from #16 and probably should be implemented either together or after the data cascade is implemented.

xm should be able to render collections of data. For this I imagined we could use a <fill> tag with a new attribute called from (name can be changed).

from takes an array of flat objects (a string of JSON), iterates over them and repeats its content while filling the slots:

EniH6fWW4AAgNU1

For advanced use cases from accepts:

  • glob patterns (grab fills from other HTML files)
  • JSON file paths
  • path to a JS module that exports an array or a function
  • path to a JS module that exports an async function

EniI0OWXcAITSQ0

The async function version is super powerful 💣

async functions can be used to fetch data from an API, database and perform any other asynchronous operation!

EniJ0LmXYAAMQXk

Document title rendered as `<slot name="title"></slot>`

I can't seem to get slots that are in head > title filled.

I run xm on a folder with 2 files, base.html and index.html, that looks like this:

<!-- base.html -->
<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf8"/>
        <title><slot name="title"></slot></title>
    </head>
    <body>
        <slot name="body"></slot>
    </body>
</html>
<!-- index.html -->
<import src="base.html">
    <fill name="title">
        The title goes here!
    </fill>
    <fill name="body">
        <h1>Hello world!</h1>
    </fill>
</import>

xm's output is:

<!DOCTYPE html>
<html>
    <head>
        <meta charset="utf8">
        <title><slot name="title"></slot></title>
    </head>
    <body>
        
        <h1>Hello world!</h1>
    
    </body>
</html>

The title slot is not being filled.

RFC: expressions

xm is not a full blown templating system and will probably stay like this.

However I am thinking about implementing an extension (a separate PostHTML plugin) to add support for expressions and perhaps loops.

Please give this description a 👍 if you like this proposal or a 👎 if you'd rather use an existing PostHTML plugin like posthtml-expressions


sample syntax - see description

The syntax would be {xm:expression} where expression is a reference to a fill value or any other constant defined by the user via config file and is part of a serialized env object passed to the plugin as an option.

// configuration passed to the posthtml plugin
{
   env: { posts: collectPosts() }
}

Additionally expression can be an arrow function that takes one parameter - the fill value - and transforms that value:

{xm:domain => `www.${domain}`}

Finally I might add some built-in helpers to make things like url encoding easy:

{xm:permalink|encodeURIComponent}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.