Giter Club home page Giter Club logo

franklin.jl's Introduction

Franklin: a Static Site Generator in Julia.

Lifecycle Build Status Coverage

Franklin is a simple static site generator (SSG) oriented towards technical blogging (code, maths, ...), flexibility and extensibility. The base syntax is plain markdown with a few extensions such as the ability to define and use LaTeX-like commands in or outside of maths environments and the possibility to evaluate code blocks on the fly.

Franklin has a channel #franklin on the Julia slack, this is the best place to ask usage questions.

Note: I'm looking for people with web-dev chops who would be keen to help improve and enrich the base themes available at FranklinTemplates.jl, even if you're not super confident in Julia. More generally, if you would like to work on something or fix something in either Franklin or FranklinTemplates, please reach out on Slack, I will gladly help you get started.

Docs

Go to Franklin's main website. For users already familiar with Franklin you might also find these demos useful. Ifihan Olusheye also wrote this blog on building a blog with Franklin.

Important notes

  • if, upon deployment, your website doesn't seem to apply CSS, you likely forgot a step, please see here.
  • it is currently recommended to switch off pre-rendering and minification (you can do this by passing prerender=false, minify=false to the optimize(...) call in your deploy script), the corresponding logic will be removed in future version of Franklin as it's tricky to maintain and caused too many issues.
  • if you're getting warning messages about some JS library not being found on your computer, you can safely ignore this.

Key features

  • Use standard markdown with the possibility to use LaTeX-style commands and generating functions written in Julia
  • Simple way to introduce div blocks allowing easy styling on a page (e.g. "Theorem" boxes etc.),
  • Can execute and show the output of Julia code blocks,
  • Easy HTML templating to define or adapt a given layout,
  • Custom RSS generation,
  • Simple website optimisation step:
    • compression of HTML and CSS of the generated pages,
    • optional pre-rendering of KaTeX and highlighted code blocks to remove javascript dependency,
  • Extremely flexible and extensible.

See the docs for more information and examples.

Examples

Some examples of websites using Franklin (if you're using Franklin with a public repo, consider adding the "franklin" tag to the repo to help others find examples, thanks!)

Adapted templates (i.e. starting from one of the available themes)

Custom templates (i.e. migrating an existing design)

Getting started

With Julia ≥ 1.3:

pkg> add Franklin

you can then get started with

julia> using Franklin

julia> newsite("MyNewSite")
✔ Website folder generated at "MyNewSite" (now the current directory).
 Use serve() from Franklin to see the website in your browser.

julia> serve()
 Initial full pass...
 Starting the server...
✔ LiveServer listening on http://localhost:8000/ ...
  (use CTRL+C to shut down)

Modify the files in MyNewSite/src and see the changes being live-rendered in your browser. Head to the docs for more information.

You can also start from one of the templates by doing something like:

julia> newsite("MyNewSite", template="vela")

You might want to put the following command in your .bash_profile or .bashrc as a way to quickly launch the server from your terminal:

alias franklin=julia -O0 -e 'using Franklin; serve()'

Heads up!

While Franklin broadly supports standard Markdown there are a few things that may trip you which are either due to Franklin or due to Julia's Markdown library, here are key ones you should keep in mind:

  • when writing a list, the content of the list item must be on a single line (no line break)
  • you can write comments with <!-- comments --> the comment markers <!-- and --> must be separated by a character that is not a - to work properly so <!--A--> is ok but <!---A---> is not, best is to just systematically use whitespace: <!-- A -->.
  • be careful writing double braces, {{...}} has a meaning (html functions) this can cause issues in latex commands, if you have double braces in a latex command, make sure to add whitespaces for instance write \dfrac{1}{ {101}_{2} } instead of \dfrac{1}{{101}_{2}}. In general use whitespaces liberally to help the parser in math and latex commands.
  • (as of v0.7) code blocks should be delimited with backticks ` you can also use indented blocks to delimit code blocks but you now have to opt in explicitly on pages that would use them by using @def indented_code = true, if you want to use that everywhere, write that in the config.md. Note that indented blocks are ambiguous with some of the other things that Franklin provides (div blocks, latex commands) and so if you use them, you are responsible for avoiding ambiguities (effectively that means not using indentation for anything else than code)

Associated repositories

Licenses

Core:

  • Franklin, FranklinTemplates and LiveServer are all MIT licensed.

External:

franklin.jl's People

Contributors

aviatesk avatar csertegt3 avatar dependabot[bot] avatar dilumaluthge avatar fkastner avatar fredrikekre avatar github-actions[bot] avatar hyrodium avatar kellertuer avatar kescobo avatar luraess avatar mcognetta avatar mossr avatar paniash avatar pfitzseb avatar remi-garcia avatar rikhuijzer avatar saransh-cpp avatar seelengrab avatar shashi avatar sosuts avatar storopoli avatar terasakisatoshi avatar theogf avatar timholy avatar tkf avatar tlienart avatar totalverb avatar wikunia avatar zlatanvasovic 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  avatar

franklin.jl's Issues

If-Else

add possibility of an else statement. Suggested syntax would be

[[ if ... 
][ else ... 
]]

so the ][ would act as separator.

parser constraints

  • cannot use explicit \n
  • cannot define a math environment in a newcommand so for example
\newcommand{\blah}{$x+y=1$}

would not be ok because you'd need to re-parse after the replacement to. (note that it could be done, but would require gymnastics)

  • cannot use latex commands in escaped blocks such as code

Allow for draft pages

Pages that would be visible locally but not pushed.

Need to think about how exactly they would be linked to. Maybe best is to just generate pages that don't get linked to as draft-....

only look at tokens for given block

currently in find_lxcoms! and also find_commands, the enumeration is on everything and we check if it's within the block, and do this multiple times. would be better to keep track.

Using FileWatching

might be nice to use the proper tool for the job instead of the try loop. An example drawn from a Bukdu issue:

using FileWatching

dir = "."
fm = FolderMonitor(dir)

function reload_chrome()
   run(`osascript chrome.scpt`)
end

watching_files = ["test.css"]

loop = Task() do
    while fm.open
        (fname, events) = wait(fm)::Pair
        println("fname ", fname)
        fname in watching_files && reload_chrome()
    end
end
schedule(loop)

live-serving with browser-sync

While unclear how to do this with WebSocket etc, here are pieces to an alternative

installation of browser-sync

npm install -g browser-sync

in .bash_profile

export LOCAL_IP=`ipconfig getifaddr en0`
alias serve="browser-sync start -s -f . --no-notify --host $LOCAL_IP --port 9000"

background task in Julia

(the run syntax is likely only ok on unix)

try  
  tbs = @async run(`browser-sync start -s -f . --no-notify --logLevel silent`)
  # ... 
  Base.throwto(tbs, InterruptException())
catch x
  if isa(x, InterruptException)
    println("ok")
  end
end

or something of the form.

Eqref (and hyperref) handling

it should be doable to keep track of \label{...} and keep some form of count then restitute the whole thing when a \eqref or \ref (\\ref{([^{}]*)}) is seen.

In html processing, should use an anchor (see tutorial)

Actions

  • implement something that processes \command{...} (see #5 also)
  • have another dictionary (not JD_LOC_VARS because you don't need to keep track of types) to keep track of names->number pair.
  • might want to keep macro variable such as section variables that are incremented every time a # or ## etc is seen. could also use that for section numbering (if required)

Abuse of short circuits may not be great

The code uses a number of short circuits of the form

boolean && continue

this is potentially inconsequential. However for more complicated scenarios involving function calls, short circuits are probably best not used as CPUs may fail to optimise there (https://en.wikipedia.org/wiki/Short-circuit_evaluation).

Therefore their use seems justified either if

  • the case is very simple (eg above)
  • the secondary function is very slow (fast_check && slow_call)

and it should be documented as such.

Further, the use of

a = boolean ? v1 : v2

is probably best replaced by

a = ifelse(boolean, v1, v2)

again to help with CPU predictions. The difference being that in the first case v2 is only evaluated if boolean is false whereas in the second case both v1 and v2 are evaluated. So the ? construction should be used only if v2 is significantly slower than v1 and v1 should always be the fast operation.

test image insertion + SVG management

Basic Image insertion should work out of the box with the usual markdown syntax.

In some future, it may be that we'd generate images directly from julia code (in SVG) for example from PGFTex or something and plug them in a-la weaver. Would be good to pre-test SVG and see how easily it handles that.

Dealing with `<p>` and `</p>`

so now that we're working with block, we have to be a bit careful about the adding and the removing of <p> and </p>.

I'm not sure whether this is going to cause any bugs, but it may on more complex documents, should keep an eye on this and experiment.

Cache parsing of latex def

this may be a bit tricky to do and would purely be for speed improvements.

Atm, when a command is seen, the definition is plugged in then the resulting plug is re-processed. If the same command is used mutliple times the same procedure is repeated.

This is a bit wasteful and could probably be optimised away by storing the information as we progress. No clear idea how to do this well and can probably be pushed back somewhat.

Number of passes growth with number of tokens

So with pretty much every token, a full linear pass over the markdown is done. This means a lot of useless passes. While all of it still probably takes <10ms for a standard page, it feels like it's a slippery slope.

Building a more systematic parser is probably not trivial, using a generic parser is probably hard and overkill. Steps that could be done:

  1. tree-based parsing to stop parsing bits where there's obviously nothing
  2. doing a first pass to denote areas where there may be tokens of interest, using this for the tree.
  3. using the matching token thing as ways to split the tree.

Probably good to first benchmark as it is with a test input file and then see whether another way is better.

Const vs Global vars

JD_GLOB_VARS gets set explicitly after reading config.md and may even get set later on, so it's definitely not a const. It should be a global.

The JD_LOC_VARS is only used as a template that gets copied for every page.

Either way it seems that using const both times is a bit dodgy. May want to rethink this.

Extract default title from first # element

The target page variable is title which can be set in markdown via

@def title = "the title"

however if not given, there should be a default one extracted from the first # block.

Parse CSS as well

should allow rudimentary variables in CSS (fill-type). For colours, ratios, etc

  • would require tracking of modifications + processing

Better use of Strings

So there seems to be some exotic stuff going on when iterating through a string that may contain strange characters. See the use of length (https://docs.julialang.org/en/v0.6.1/manual/strings/) also maybe use prevind, nextind or something like that to iterate through the string rather than do index arithmetic.

This may not change anything for "non exotic" strings but in the case where someone would use an emojii or some symbol outside the standard pane, there could be problems...

Minify output

Can use something like a generic minifyer to do the trick at the end.

Potential problem: the files should be replaced so that in the git-push to (for example) git pages, it's the minified version that is served.

Could also maybe directly apply it on every file that is compiled but that would make things slower. Could also minify stuff yourself removing whitespaces or whatever.

Bullet points starting with maths are not properly converted

This kind of markdown:

* $f$ is a function that... 
* one can compute ...

leads to this kind of html

<ul>
<li></li>
</ul>
\(f\) is in the set \(\Gamma_0(X)\) of convex functions on \(X\) that are <em>proper</em> and <em>lower semi-continuous</em>,</p>
<ul>
<li><p>one can compute a gradient or subgradient of </p>
</li>
</ul>

The second one is fine but the first one is not. This may have to do with the order in which things are done and eventually md2html is called.

What it does:

  • only parses a * then closes it as a standalone <ul></ul> with a single, empty, <li></li>
  • then plug in the maths thing

Fix codecov?

unclear what's failing but the reports are not analyzed. It does not look like it's an issue with the Travis CI. (though it only appeared after 0.7, maybe look at Diff*Eq.jl)

Modularise process_files.jl

The function is now too big and there are some parts that should be reasonably easy to cut out.

  1. the continuous checking part
  2. the markdown transformation part
  3. going through files and populating a dictionary accordingly

also really need to write some doc or think in more details about issues (currently all NOTE and TODO in the code).

  1. dealing with assets that are changing
  2. dealing with infra files that are changing and must cause a re-compile
  3. having some verbosity level indicating what's being seen and what's going on

checking commands get appropriate number of argument

if only go with match_curly_braces, could take braces that are not connected in case a command has too few args.

Can do this later and assume (for now) that commands are properly written.

A simple way could be to check that the {}{} are all contiguous, so opening braces must be adjacent to the previous closing brace. (Latex also doesn't allow spaces afaik)

Using HTTP.jl for serving

using HTTP
HTTP.listen() do req::HTTP.Request
     req.target == "/" && return HTTP.Response(200, read("index.html"))
     file = HTTP.unescapeuri(req.target[2:end])
     return isfile(file) ? HTTP.Response(200, read(file)) : HTTP.Response(404)
end

does the job (needs a REPL).

  • add a catch for InterruptException
  • check if it does live updating of things?
  • how to interweave with the judoc(single_pass=false) ?

Cleanup readme

move todo stuff to issues here,

move specific brainstorm stuff to relevant files.

Managing dates

  • dates management, Dates.today() is no good, every time the file is recompiled (may be often). Or should just not re-interpret if there's no diff (then ok). The latter would require keeping track of the files + time of last modification in a hidden file that is gitignored.
  • if empty, nothing should appear.
  • dates should all have the same format (atm, it could be different).
Dates.format(now(), "U dd, yyyy")
Dates.format(Date(2018, 5, 15), "dd U yyyy")

See also formats.

Work out system for infra-files

  • _html/
  • _css/
  • _libs/

should be kept somewhere, ideally an auxiliary repo (potentially with submodularity?). Ideally not kept in this one as it will clog the repo (and make it appear as a bloody js repo)

repo organisation: separate MD and HTML parsing

Instead of having one conv folder, use two folders\

  1. one for everything markdown related
  2. one for everything html related

basically should be related to the general workflow

  1. markdown processing
  2. (base markdown parsing)
  3. html processing

use of appropriate data structure for blocks in parser

at the moments, re-creating allnewblocks several time which is obviously not very clean.

It doesn't really matter because it's small but really that stuff should be done with a LinkedList or something. Could use DataStructures.jl but it's a bit obscure. Might be just easier to do your own stuff here.

want

  • easy insert at middle of list
  • easy linear traversing of list

interweave_rep might not be necessary

so this seems to work quite well, possibly because of pointer stuff:

t = raw"""
  this is some text blah
  and some more blah yes so blah
  and then more
  here blah"""
for m  eachmatch(r"blah", t)
  t = replace(t, r"blah", "YA")
end
println(t)

returns the appropriate stuff (no messing with eachmatch on a transforming string:

this is some text YA
and some more YA yes so YA
and then more
here YA

that means that interweave_rep can be simplified using that trick (maybe).

Long-term tracking of files to avoid initial full path

  • have a hidden file keeping track of all files (basically something corresponding to the watched_files dictionary).
  • when compiling (without a forcing argument), check if there's a diff or new files
  • recompile what has diff-ed.

Nesting

Nesting is currently not allowed (in that it will cause things crash, it won't raise an error)

html

  • for [[ if ... ]] blocks, they allow a single level of {{ }} nesting
  • the {{ ... }} blocks do not allow nesting
  • [[ ... ]] blocks do not allow nesting

md

  • the @@... div blocks allow math blocks within them but no nesting of other div blocks
  • \com{..} (future) should maybe allow nesting in that the inner, most nested, should be replaced first etc.

Actions

  • either raise a proper error
  • or allow nesting

it may require to actually implement a simple open/close function which counts and builds a stack which is then further processed or something. (that would also allow to handle problems by indicating when parens are not found)

Also nesting would require to use some form of recursive parsing. Having a generic function which extracts stuff based on delimiters is probably a good idea.

--> see README.md for a prototype of a function that does this in some level.

Extract code blocks early

Since will look at allowing latex, the curly braces in code blocks (e.g. in types in Julia) would clash.

These should be extracted early and potentially fed back in just before the HTML parsing which handles block codes just fine.

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.