GithubHelp home page GithubHelp logo

abelljs / abell Goto Github PK

View Code? Open in Web Editor NEW
411.0 411.0 37.0 2.35 MB

A Low-Level, Framework Agnostic, Highly Flexible Static-Site-Generator to help you build Static Sites on a smaller learning curve ๐ŸŒ€

Home Page: https://abelljs.org

License: MIT License

JavaScript 2.43% HTML 15.09% TypeScript 64.40% CSS 3.26% SCSS 5.26% MDX 9.56%
abell abelljs hacktoberfest javascript static-site-generator

abell's People

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

abell's Issues

Question: If you want to create a plugin for Abell, what data and functions you would expect to be exported out of abell?

This is how Abell works (as of v0.2.x)

  1. Get all the necessary data in programInfo variable (Reads the theme/[$slug]/index.abell, reads the abell.config.js, reads the directories in content/, prepares all the necessary variables)
    (Code: https://github.com/abelljs/abell/blob/master/src/content-generator.js#L89)
  2. build(programInfo) is called which loops through all .abell files and calls generateHTMLFile(path, programInfo) when it's a normal .abell file and generateContentFile(path, programInfo) when its [$slug]/index.abell.

Possible plugins

  • RSS Feed (Thanks @akash-joshi for the suggestion)
  • PWA (Way to create manifest.json, service workers, etc)
  • SiteMap Generator

I would love to know suggestions and feedback on how we can possibly make the plugin system.

Expose beforeWrite function for plugins

Is your feature request related to a problem? Please describe.
There should be some way we can change the content before creating files, this way we can allow plugins that add new variables or content to the .abell files.

Describe the solution you'd like

From plugins we should be able to do

function beforeRender(abellTemplate) {
  // ... operations
  return newAbellTemplate;
}
module.exports = { beforeRender }

This function should run before we call abellRenderer.render function while turning .abell files to .html

Additional context

Changes in Code

So this is the code that exposes afterBuild function for plugins (the code may move a little up or down if I change file in next commits) https://github.com/abelljs/abell/blob/main/src/commands/build.js#L102-L114

To run that function before the render, we will have to expose the function from https://github.com/abelljs/abell/blob/main/src/utils/build-utils.js#L219 before calling abellRenderer.render

Testing plugins locally

After following the Local Setup Guide from CONTRIBUTING.md

  • cd examples/with-plugin
  • abell build

This will run the plugin example from the example folder .
You will have to add a sample beforeRender function in plugins/index.js to run beforeRender as well.

๐Ÿ› Sometimes the site content goes blank in dev-server

It's kind of hard to explain,

When you open dev-server and keep changing the content, sometimes the page goes blank then after refreshing again, the content comes back. Apparently the problem seems to be with readFile functions, Even if a file has content they sometimes return blank string in dev-server.

How to reproduce:

  1. After local setup, run npm run dev:serve
  2. Go to demo/[content]/index.abell file and keep changing something there continuously.
  3. After several refreshes, the content will go blank and after refreshing again it will come back.

ESLint plugin for abell

Is your feature request related to a problem? Please describe.
ESLint is the most popular javascript linter. Since abell is executing a lot of javascript in the .abell files, it would be awesome if you can allow eslint to be used with abell

This might also allow for a good linting solution for abell altogether

Describe the solution you'd like
Make a eslint-plugin-abell which allows usage of abell files with eslint.

This will need a bit more exploration of eslint and we can see if that can even achieve this or not.

Minify Build Output

Is your feature request related to a problem? Please describe.
The current abell build output is not minified. If we minify it can decrease the bundle size and eventually help loading it faster

Describe the solution you'd like

We have few ways to implement this,

  • Have it integrated inside abell so we will minify before we call fs.writeFile
  • Build a separate plugin that reads output files and writes the minified text into it.

The first one will be ideal if we find a minifier which has less or almost no subdependencies.

If the minifier has a large dependency tree, it will be better to maintain it separately as part of official plugin. In this case we can keep it preinstalled in some of the starters. Also with this user can opt out if they are building a small website where minifying isn't needed

Unit tests fail when port 5000 is occupied

Describe the bug
Unit tests fail when there is an application running on port 5000.

npm test and npm run test:unit fail when there is an application running on 5000.

To Reproduce

  • Start a process in Port 5000.
  • Run npm test or npm run test:unit
  • The tests fail.

Expected behavior
The server should listen to the next ports.

Screenshots
For npm test

image
image

npm run test:unit also gives the same result: https://pastebin.com/ricHw8ug .

Specs:

  • Abell Version: 0.6.4
  • Node Version: 12.18.0
  • Operating System: Windows 10 Home

To have something to wrap code that will run on client side

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
The current syntax of abell can in some way encourage users to do {{ new Date() }} however, this will can give unexpected results.

From syntax, it looks like it will render today's date (since this is what it will do in React or other framework) but rather it will render the build time date.

Describe the solution you'd like
A clear and concise description of what you want to happen.

Maybe we can actually have something like,

<div>{{ renderThisOnClientSide('new Date()') }}</div>

which will render the client-side date and not the build time date.

Additional context
Add any other context or screenshots about the feature request here.
Input:

<div>{{ renderThisOnClientSide('new Date()') }}</div>

Output:

<div><span id="abell-element-1"></span></div>

<!-- Somewhere in javascript -->
<script>document.querySelector('#abell-element-1').innerText = new Date()</script>

Better way to write components/partials

Is your feature request related to a problem? Please describe.

Currently, components are just JS files that return string of html css javascript, if a component needs to return javascript, the code loooks super uglyyy.

Describe the solution you'd like
A component similar to Vue component but rendered with Abell instead

Additional context
Idea:

// Footer.abellc
<AbellComponent injections>
<template>
  <footer>My Footer! {{ injections.footerLinks }} <span id="year"></span></footer>
</template>
<style>
  footer { padding: 10px; }
</style>
<script>
  document.querySelector('#year').innerText = new Date().getFullYear();
</script>
</AbellComponent>

Error display fix when content/index.md is changed

Describe the bug
A clear and concise description of what the bug is.
When top-level index.md from content/ folder is changed, error is logged in the terminal and complete rebuild is performed

Expected behavior
A clear and concise description of what you expected to happen.
Should not throw error, and perform build.

Error on writing unavailable path in $importContent is not understandable.

Describe the bug
Hi, so like we care about what works, in static-site-generators we will also have to care about what doesn't work. And when something doesn't work, there should be a proper error message that mentions why it is not working.

To Reproduce
In any .abell project, go to [$path]/index.abell and write $importContent(undefined + '/index.md').

This will throw an error which is completely not understandable to users.

Expected behavior
It is supposed to show a better message that explains what is need to be changed.

Additional context

We can add try catch around markdown reading in importAndRender function in src/utils/build-utils.js

Error handling to avoid exiting the dev-server, if error occurs.

Currently, if you're working in dev-server and an error occurs, let's say you write a variable that is undefined, In this case the dev-server is closed after throwing the error.

How to reproduce

  • abell serve after setting up this repo locally.
  • In demo/index.abell, write a variable that is not defined anywhere.
  • This will throw the error in terminal and will close the dev-server.

How it should work

  • It should throw error but should not exit the dev-server.

Code help

serve function handles the dev-server, if we add try-catch for error handling there, it should avoid exiting the server I believe.

Build all .abell files from src

Currently, we're only building src/index.abell and src/template/content.abell file. It would be very helpful if we could build all the .abell files.

How to approach issue:
In src/action.js file, There is generateHTMLFile('index', programInfo); function that builds the file. We'll have to read the directory and find all the .abell files and then loop over them and call the generateHTMLFile function.

Benchmarks

Benchmarks are important for monitoring performance of a tool. Since abell is a very core part of every website built with it, we need to make sure abell remains performant and it can provide a good user experience.

Right now we have no benchmarks for abell and that will remain the case for a while as abell is being shaped but we need to start figuring benchmarks out at some point. We need to decide a proper metric and test other related techs along its line.

The most important metric I am interested is build time right now

Auto-calculate ignoreInDist array

ignoreInDist array holds the directories/files that are supposed to be ignored in dist since they are only needed for build-time. Currently, we have to define which files to ignore in abell.config.js

Instead, we can calculate which files were required during the build time and ignore those files.

Multiple templates not working

Describe the bug

theme/
    [$path]/
        - index.abell
        - example.abell

With the above directory format, abell should also generate example.html in all content directories.

Add contentTemplatePath option in abell.config.js

This is what abell.config.js file looks like right now

module.exports = {
  sourcePath: 'src',
  destinationPath: 'dist',
  contentPath: 'content',
  templateExtension: '.abell'
  globalMeta: {
    siteName: 'Abell Demo'
  }
}

and the contentTemplatePath is currently static into the code src/[$slug]/index.abell. We need to make this dynamic so that user can set the path from config file and use that file to generate content

[IDEA, POLL] Importing variables rather than having it available by default.

Option 1

index.abell

{{
  const { globalMeta } = require('abell');
}}

<html>
<body>
  {{ globalMeta.siteName }}
</body>
</html>

[$path]/index.abell

{{
  const { $contentObj, $path } = require('abell');
  const meta = $contentObj[$path];
}}

<html>
<body>
  {{ meta.title }}
</body>
</html>

vs

Option 2 (The current way)

index.abell

<html>
<body>
  {{ globalMeta.siteName }}
</body>
</html>

[$path]/index.abell

<html>
<body>
  {{ meta.title }}
</body>
</html>

EDIT:

Option 3

index.abell

{{
  const { globalMeta } = variables;
}}

<html>
<body>
  {{ globalMeta.siteName }}
</body>
</html>

[$path]/index.abell

{{
  const { meta } = variables;
}}

<html>
<body>
  {{ meta.title }}
</body>
</html>

We can change name of variables in option 3 to self, globalVariables, abellVariables, or abell

I kinda like,

const { globalMeta } = abell;

Can you all drop 1, 2 or 3 in the comments and tell which one you prefer, and why?

Maintain the folder structure in 'content'

Is your feature request related to a problem? Please describe.
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
Current abell can only understand content/ that has following structure

content/
  -> my-cool-blog
    -> index.md

Describe the solution you'd like
A clear and concise description of what you want to happen.
It should also support

content/
  -> my-section
    -> my-cool-blog
      -> index.md

So in the output also we'll get the same path.

Additional context
Add any other context or screenshots about the feature request here.
This will need major refactoring of the whole abell.

Asynchronous functions in plugins not supported

Describe the bug
There is no way to make beforeBuild function from plugins, asynchronous. It is a common use-case that someone would want to fetch data in the plugin before building the files.

Expected behavior

Plugin with this code should work

async beforeBuild(programInfo) {
  await fetch('example.com');
  // write into file and other operations.
}
module.exports = { beforeBuild };

Way to override $createdAt value from meta.json

Currently when you create a folder and index.md, the date of folder creation is taken in $createdAt. But this date can have unexpected changes. Let's say you wrote a blog in 2018 and you just copied it here. In that case, it will say that the blog was created today and not in 2018.

If a user mentions $createdAt in meta.json of content. Then we should override the value.

The code that deals with $createdAt is at https://github.com/abelljs/abell/blob/master/src/content-generator.js#L66

Here's a catch!
The default $createdAt is a JavaScript Date object. but we can't write a date object in JSON. So in JSON we should be able to write a human-readable value and convert it into a date object in the getContentMeta function

Feature: Hot module replacement

Just persisting an idea for the future. I know it is a lot of work.

Is your feature request related to a problem? Please describe.
Right now the dev server reloads the whole app in order to show the updated content. Most popular static generators or apps use hot module replacement to provide a much smoother experience

Describe the solution you'd like
Implement a hot module replacement strategy for abell so that it can provider a richer dev experience

Additional context
React hot loader(https://github.com/gaearon/react-hot-loader) (note: deprecated in favour of fast refresh)
webpack hot loader: https://webpack.js.org/concepts/hot-module-replacement/

Function in function to read JSON

Hi,
Abell seams pretty cool but I can't find a way to have a function in an other function to read "complex" JSON

Exemple
I have a JSON file

[
	{
		"title":"Blabla", 
		"tags": ["internet", "ethic"],
		"images":["blabla.png"],
		"date":"aoรปt 2019", 
		"sources":{
			"url":"https://github.com/", 
			"description":"Github website"
		}
	}
       {...}
]

And I want to make a .map() in another .map() to add tags and sources information to a page. I try different stuff but it's look like Abell don't want to make that

Is there a way to do it ?

Thanks in advance
Have a nice day ๐ŸŒž

How can we tell user where the 'globalMeta' variable is coming from?

So currently if you've seen, globalMeta object is accessible from any .abell file directly.

Do you think it can confuse people about where the globalMeta is coming from?

How about having something like this on top of .abell file?

{{ import { globalMeta } from './abell.config.js' }}
<!DOCTYPE HTML>
<html>
// ...

This will have its cons though... This will give too much flexibility to the user on where he wants to import from so he can put any .json or .js files there. Which means we will have to read the templates first and then read what user is importing from (currently since we already know what to import, we can keep all those variables ready and inject them in renderer. This makes it run faster).

On one hand, I feel it is fine since it is just like having window object in JavaScript. We don't know where window comes from but it's just there.

I would like to get some feedback on this

Improve README

Right now readme doesn't display any code example to display the beauty of abell. That can mean potentially loss in conversion of users.

We should improve the readme.

i18n out of the box

If we could have content like this,

content/
    |- my-cool-blog/
        |- index.md
        |- index_zh-Hans.md
        |- index_hi.md

so if a user prefers Mandarin, he will get content from index_zh-Hans.md (zh-CN is the code of Chinese Simplified)

Use single port to run websocket and http server in abell-dev-server

Is your feature request related to a problem? Please describe.
This has explaination of how abell-dev-server currently works #51

Describe the solution you'd like
I just realized both servers can run on same port.

This is the example from ws library

const fs = require('fs');
const https = require('https');
const WebSocket = require('ws');

const server = https.createServer({
  cert: fs.readFileSync('/path/to/cert.pem'),
  key: fs.readFileSync('/path/to/key.pem')
});
const wss = new WebSocket.Server({ server });

wss.on('connection', function connection(ws) {
  ws.on('message', function incoming(message) {
    console.log('received: %s', message);
  });

  ws.send('something');
});

server.listen(8080);

Additional context

src/abell-dev-server has the server.js and http-serve.js. server.js file has code to start a websocket server and send reload command to http server and http-serve.js file runs a http server.

How do dev-servers of other frameworks/libraries work on single port?

In abell-dev-server, we have to run a http server on localhost:5000 and a socket server on localhost:3000.

Then we connect the http server to the socket server and every time a change occurs in a file, we send a reload command to http server through websocket.

How is this supposed to work without websocket server?

Multiple components in single file

Is your feature request related to a problem? Please describe.

<AbellComponent name="Footer">
<template>
</template>
<style>
</style>
<script>
</script>
</AbellComponent>

<AbellComponent name="Navbar">
<template>
</template>
<style>
</style>
</AbellComponent>

Rough idea.

Inline components

Is your feature request related to a problem? Please describe.
Right now everytime you need to make a new component, you will need to make a new .abell file. It works fine for the most part but it is very ideal for quick iteration or if you want to reuse some logic in the same component. You will still need to spill the reused part into its own file which creates file system mes..

Describe the solution you'd like
Design Inline components for abell. Right now I don't have a concrete idea in mind as abell files right now are like a single file component. This issue is meant for persisting this idea for the future.

Additional context
I would look into Vue.js as they have kind same concept of a single file component which vue community seems to love. Maybe we don't need this altogether.

Create docs from READMEs in project

Something like Jekyll and Eleventy, if we run a command abell build --from-readme, it should create a single page with content from README in it.

Still not sure about --from-readme command, need to find something else.

Prefetching page on link hovers

We can add JavaScript that will preload the page if the link to that page is hovered. Gatsby does that and I've seen other websites like DEV.to, Flipkart doing that.

This will help us load the pages faster!

Spread user-defined attributes in script and style tag in output

In components, User should be able to write,

<AbellComponent>
// ....
<style rel="preload" onload="this.rel='stylesheet'; this.onload=null">
/* css */
</style>
</AbellComponent>

and in output it will be rendered as,

<style rel="preload" href="bundled-css/main.css" onload="this.rel='stylesheet'; this.onload=null" />

Inlined Markdown

Describe the solution you'd like

<html>
 <body>
   <h2>About Me</h2>
   <AbellMarkdown>
     Hi, I am **Saurabh**. I love making websites. 
     You can follow me on [Twitter at saurabhcodes](https://twitter.com/saurabhcodes)
   </AbellMarkdown>
</body>
</html>

Idea: Abell renderer for emails

Is your feature request related to a problem? Please describe.
I think abell would be a very good fit for writing email templates. The syntax is close to html.

Describe the solution you'd like
Most like we will need to make some abell components which will mimic the html email mess which are the tables. I can share more ideas about that after we release components.

Additional context
(Hm, just dropping an idea right now.)

Have all assets in content/:slug/assets folder instead of top level

Describe the solution you'd like
A clear and concise description of what you want to happen.

Having images in content/:slug/ can make it difficult to track which are static files and which are only needed for build (meta.json, index.md etc).

By having all the images in content/:slug/assets, we can ignore files in top-level and make assets statically accessible.

Unit tests for dev-server

Currently, there are absolutely no tests for dev-server. We do test build function which dev-server uses internally but there are other things like looking for changes when a file is changed which are not tested on npm test

Scope Styles and Scripts

Is your feature request related to a problem? Please describe.
Current styles and scripts in Abell Components are not scoped. We need a way to scope them to a particuar component

Describe the solution you'd like

<style scoped>
  a { color: #f30; }
</style>

This style will be only applied to the anchor tags of that particular component

build and serve error

Describe the bug
Hey,
When I run npm run dev:serve or npm run dev:build I always getting this error
build

serve

Add --ignore-plugins flag to abell serve

Is your feature request related to a problem? Please describe.

Plugins can have additional sources (CHANGELOGS, READMES) which can slow down the development process if you don't want to test them on every run.

Describe the solution you'd like

Calling abell serve --ignore-plugins should ignore the plugin execution.

Approach

  1. We will have to register this flag in bin/abell.js
  2. Add flag value true or false to programInfo in src/commands/serve.js
  3. On true, ignore calling executeAfterBuildPlugins and executeBeforeBuildPlugins functions in the serve.js
  4. ignore calling executeBeforeHTMLWritePlugins from src/utils/generate-site.js

This issue can be a good start for beginners so if you're experienced and comfortable with GitHub, Please look for other issues and leave this issue for beginners to that they can get started :D

description issue

I created a new folder with description at meta.json but it not changes in main page

{ "title": "array.Push()", "description": "Javascript array.push() method." }

look at tha description in main page

Screenshot from 2020-06-18 10-31-52

Serve fails when new folder is created in content

Describe the bug

It is a common use-case where you will have a running server and you add a new blog by creating a folder, however, this is not possible because the serve fails and does not recalculates the new changed contents.

To Reproduce

Run dev-server with abell serve and create new folder in content

Expected behavior

Should not fail, recalculate directories, rebuild abell.

Dev server: listen on next available port if port 5000 is not free

Is your feature request related to a problem? Please describe.
Pretty self explanatory. Most popular dev server listen on the next avaliable port if the default port is not available. This saves you from finding the process which is consuming that port.

Right now abell just crashes:
image

Describe the solution you'd like
Listen on next available port if port 5000 is occupied. Do not do this if user has specified the port.

Additional context
https://github.com/facebook/create-react-app/blob/8e761d19d14f47afdbbcfa6e19ed50c8ea1a63f4/packages/react-dev-utils/WebpackDevServerUtils.js#L448

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.