Get Cape, a no-bullshit mobile provider focused on privacy and security, and get $20 off your monthly bill.

Publii: The good, the bad, the uglii

This site is currently being generated using Publii, a relatively simple, open-source, cross-platform, off-line content management system and static site generator all-in -one. If that sounds complicated, you can sleep well tonight knowing that Publii is aimed at us technically challenged users. It's even easier to use than WordPress and since the result is static HTML, there's a lot less worry regarding security. Matter of fact, Publii is currently the only easy to use, off-line, all-in-one CMS/SSG combo i'm aware of that doesn't require a masters degree in web development (slight exaggeration) and this makes it an endangered species that is absolutely necessary in the age of Big Tech and surveillance capitalism.

The fact that there is such a lack of simple website authoring software these days is decidedly disappointing and i think much of the reason for this is a reliance on wildly unethical, privacy-hating, data gulping garbage dumps like FaceSpook, Twatter, TwitTok, Instaspam, etc.. This wasn't always the case as there were several decent desktop WYSIWYG (What-You-See-Is-What-You-Get) website builders available back in the day, some free and open-source, however they have either evaporated or become obsolete. Funny thing is, the trendy "new" thing today is essentially a reinventing of the static site generators of yesteryear and there's no shortage of such projects either, though exceedingly few will resonate with the average person in terms of simplicity.

The majority of today's SSGs are complex, multi-component affairs that cater to the competent web developer with reasonably decent coding skills rather than the blogger who just wants to publish content and not worry so much about all the under-the-hood complexities. Anything remaining that spits out static HTML, and is at least somewhat easy to use, typically requires installation on the server side, such as WordPress. Although running publishing software on the server is the norm, i personally think this is silly and unnecessary in many cases, such as for the solo-web author or where dynamic content is not required.

Publii serves my needs fairly well, but it's not without its issues, some of them rather annoying. That said, Publii has not yet reached the 1.0 mile mark as of this writing and so it's not a finished product. With that in mind, let's beat the hell out of it anyway and see where the pieces land...

the good

  • Publii is free, open source software which is reasonably respectful of user privacy.
  • It generates static HTML with [too much] CSS and some JavaScript (assuming the default theme), though pretty much everything works for your visitors that don't want to enable JS, including the display of images.
  • With no database or CMS running server-side, security concerns are lessened and the server requirements are greatly reduced. Neither PHP or a database is needed.
  • While Publii makes it simple to build a website, it's not too dumbed-down. There's still a lot of options for configuring the appearance and functionality of the site, as well as the user interface, though to a far lessor extent in the latter case. Custom themes and post templates are all there if you want them.
  • It works off-line which could be the berries for those with crappy internet access. I think this makes perfect sense for the solo or traveling web author verses installing a bloated, server-side CMS and dealing with all the security/privacy issues that entails, it's plug-ins, a database server, PHP, etc..
  • Publii offer 2 WYSIWYG editors, at least one of which is based on the open-source TinyMCE editor, as well as a markdown editor, however this is also a sore spot.
  • It has a very nice, drag-n-drop, multi-level menu editor.
  • It supports tags, including accompanying descriptions and images if desired.
  • The UI includes a dark theme, as does the included 'Simple' theme for your website and more boxed themes are available.
  • Publii can import content from WordPress, though doing so is ill advised in my opinion since WordPress produces garbage HTML.
  • It has a plug-in architecture, though very few plug-ins are currently available and many are not free.
  • There are plenty of ways to upload/export your website including FTP, SFTP, a compressed or uncompressed archive and Git integration. There's also Netlify, whatever that is, Google Cloud, Amazon S3 and Cloudflare Pages, all of which everyone should seriously consider avoiding for ethical and privacy reasons.

the bad

  • There are very few options for styling elements of the UI which are exposed in the UI, such as font and scrollbar colors, some of which are problematic, at least with the dark theme.
  • 3 post editors seems both unnecessary and problematic. I believe a single instance of TinyMCE can reasonably cater to everyone whether they want to write using WYSIWYG (in "block" mode or not), markdown, or edit raw HTML and though i haven't looked under the hood, i suspect Publii may be using TinyMCE for all 3 editing modes which, if true, makes separating them all the more more nonsensical in my opinion. Sure, the WYSIWYG editor can create a mess if one indiscriminately copies and pastes content without removing the formatting (try Ctrl+Shift+V) so some care has to be taken, or filtering with TinyMCE which i'm sure is possible, but not implemented. The other problem with having multiple editors is that a post authored in one cannot be edited in another and this is a complaint of many users.
  • TinyMCE options are not easily exposed. For example the status bar is not enabled, a widget which can be very helpful toward avoiding messy or unintentionally nested HTML, and also when selecting content (insert a <pre> element or an image gallery and then try deleting it with only the mouse).
  • There's no option to 'sticky' a post so that it remains at the top of the blog page and, again, the developers have no intention of adding this functionality.
  • Having a static website, while a plus for some, can be a show-stopper for others. For example it's not entirely trivial (as i'm finding out) to implement a proper, privacy-respecting, self-hosted comment server and running a commercial or very large site would likely be problematic at best.
  • It's not possible to bulk add, edit, or remove tags for posts or perform some other useful bulk operations and, once again, the developers are resistant to adding such functionality.
  • There's several many annoyances with the WYSIWYG editor, such as a useless and incredibly annoying text formatting pop-up that gets in your way when a word is highlighted, and exactly which formatting icons will be displayed in the pop-up seems to be a roll of the dice. Also there's no tool-tip showing the target of a hovered hyperlink and editing the text of a hyperlink is difficult without opening the link properties dialog, yet another problem the developers have no intention of fixing. In brief, the changes they have made to TinyMCE have compromised some of it's functionality and have made working with it more difficult than need be.
  • For larger sites with a lot of content, it may require significant time to sync the local version with the remote server. For example, Publii doesn't make use of Server Side Include (SSI), so if one has 1000 posts and makes a change to the navigation menu, then all 1000 have to be re-uploaded.
  • Using the image insert function of the WYSIWYG editor as an example, you can add an image from the dedicated media folder and the link in the HTML editor will start with file:/// which Publii will then convert to match your domain upon syncing, however Publii fails to convert the URL when adding the exact same code when the source is any other folder.
  • Like WordPress, the way the media library is handled is a mess. One cannot organize content in sub-folders for example and any post which references a file in the media library results in the creation of another copy of the file. Add responsive images to that and it just gets worse. The developers seemed to have learned nothing from the super annoying shortcomings of the WordPress media library.
  • On the local side, Publii stores most of your content in an sqlite database though i'd personally prefer flat-files.
  • While there is a site-wide RSS/JSON feed, there are no tag feeds, so one cannot subscribe to a preferred topic without subscribing to all of them.

the uglii

Publii leverages a massive pile of 3rd party software including the bloated Electron framework for its UI.

click here to reveal the list as of Publii v0.44
abbrev
abort-controller
adm-zip
agent-base
agent-base
ajv
ansi-colors
ansi-diff-stream
ansi-regex
ansi-regex
ansi-regex
ansi-styles
any-base
archiver-utils
archiver
array-find-index
arrify
asn1
assert-plus
async-lock
async-retry
async
asynckit
aws-crypto/crc32
aws-crypto/crc32c
aws-crypto/ie11-detection
aws-crypto/sha1-browser
aws-crypto/sha256-browser
aws-crypto/sha256-js
aws-crypto/supports-web-crypto
aws-crypto/util
aws-sdk/client-s3
aws-sdk/client-sso
aws-sdk/client-sts
aws-sdk/core
aws-sdk/credential-provider-env
aws-sdk/credential-provider-ini
aws-sdk/credential-provider-node
aws-sdk/credential-provider-process
aws-sdk/credential-provider-sso
aws-sdk/credential-provider-web-identity
aws-sdk/middleware-bucket-endpoint
aws-sdk/middleware-expect-continue
aws-sdk/middleware-flexible-checksums
aws-sdk/middleware-host-header
aws-sdk/middleware-location-constraint
aws-sdk/middleware-logger
aws-sdk/middleware-recursion-detection
aws-sdk/middleware-sdk-s3
aws-sdk/middleware-sdk-sts
aws-sdk/middleware-signing
aws-sdk/middleware-ssec
aws-sdk/middleware-user-agent
aws-sdk/region-config-resolver
aws-sdk/signature-v4-multi-region
aws-sdk/token-providers
aws-sdk/types
aws-sdk/util-arn-parser
aws-sdk/util-endpoints
aws-sdk/util-locate-window
aws-sdk/util-user-agent-browser
aws-sdk/util-user-agent-node
aws-sdk/util-utf8-browser
aws-sdk/xml-builder
aws-sign2
aws4
b4a
balanced-match
base64-js
bcrypt-pbkdf
better-sqlite3
bignumber.js
bindings
bl
bmp-js
bowser
brace-expansion
brace-expansion
buffer-crc32
buffer-equal-constant-time
buffer-equal
buffer-from
buffer
buildcheck
cacheable-lookup
cacheable-request
call-bind
camel-case
camelcase-keys
camelcase
caseless
chownr
clean-css
clean-css
clean-git-ref
cliui
clone-response
codemirror
codemirror-advanceddialog
codemirror-revisedsearch
codemirror-spell-checker
codemirror
color-convert
color-name
color-string
color
colors
combined-stream
commander
component-props
component-xor
compress-commons
compressible
concat-map
concat-stream
config-chain
core-util-is
count-files
cpu-features
crc-32
crc32-stream
currently-unhandled
dashdash
debug
debug
decamelize
decode-uri-component
decompress-response
deep-extend
defer-to-connect
delay
delayed-stream
delete-empty
detect-libc
diff3
dom-iterator
dom-walk
dompurify
duplexify
easymde
ecc-jsbn
ecdsa-sig-formatter
editorconfig
electron
electron-devtools-installer
emoji-regex
encoding
end-of-stream
ent
err-code
error-ex
escalade
escape-html
event-target-shim
exif-parser
exit-on-epipe
expand-template
extend-shallow
extend
extsprintf
fast-deep-equal
fast-fifo
fast-json-stable-stringify
fast-memoize
fast-text-encoding
fast-xml-parser
feathericons
file-type
file-uri-to-path
filter-obj
find-up
follow-redirects
follow-redirects
forever-agent
form-data
form-data
fs-constants
fs-extra
fs.realpath
ftp
function-bind
gaxios
gcp-metadata
get-caller-file
get-intrinsic
get-stdin
get-stream
getpass
gifwrap
gitbeaker/core
gitbeaker/node
gitbeaker/requester-utils
github-from-package
github
glob
glob
global
google-auth-library
google-cloud/paginator
google-cloud/projectify
google-cloud/promisify
google-cloud/storage
google-p12-pem
got
graceful-fs
gtoken
handlebars
handlebars
har-schema
har-validator
has-symbols
has
he
hosted-git-info
html-minifier
http-cache-semantics
http-proxy-agent
http-signature
http2-wrapper
https-proxy-agent
https-proxy-agent
iconv-lite
ieee754
ieee754
ignore
image-downloader
image-q
image-size
immediate
indent-string
inflight
inherits
ini
is-arrayish
is-arrayish
is-core-module
is-extendable
is-finite
is-fullwidth-code-point
is-fullwidth-code-point
is-function
is-stream
is-typedarray
is-utf8
isarray
isarray
isbinaryfile
isomorphic-fetch
isomorphic-git
isstream
jimp/bmp
jimp/core
jimp/custom
jimp/gif
jimp/jpeg
jimp/plugin-blit
jimp/plugin-blur
jimp/plugin-circle
jimp/plugin-color
jimp/plugin-contain
jimp/plugin-cover
jimp/plugin-crop
jimp/plugin-displace
jimp/plugin-dither
jimp/plugin-fisheye
jimp/plugin-flip
jimp/plugin-gaussian
jimp/plugin-invert
jimp/plugin-mask
jimp/plugin-normalize
jimp/plugin-print
jimp/plugin-resize
jimp/plugin-rotate
jimp/plugin-scale
jimp/plugin-shadow
jimp/plugin-threshold
jimp/plugins
jimp/png
jimp/tiff
jimp/types
jimp/utils
jimp
jpeg-js
jquery
jquery-ui
js-beautify
jsbn
json-bigint
json-buffer
json-schema-traverse
json-schema
json-stringify-safe
jsonfile
jsprim
jszip
jwa
jws
keytar
keyv
lazystream
li
libvips
lie
load-bmfont
load-json-file
locutus
lodash.defaults
lodash.difference
lodash.flatten
lodash.flattendeep
lodash.isplainobject
lodash.throttle
lodash.union
loud-rejection
lower-case
lowercase-keys
lru-cache
lru-cache
ls-all
lucide
map-obj
marked
marked
material-colors
meow
mime-db
mime-types
mime
mime
mimic-response
mimic-response
min-document
minimatch
minimatch
minimist
minimisted
mkdirp-classic
mkdirp
mkdirp
moment
ms
ms
nan
nanobus
nanotiming
napi-build-utils
neat-log
neo-async
nested-sortable
netrc
no-case
node-abi
node-addon-api
node-addon-api
node-fetch
node-forge
node-slug
node-version-compare
nopt
normalize-package-data
normalize-path
normalize-url
normalize.css
oauth-sign
object-assign
object-inspect
omggif
once
p-cancelable
p-limit
pako
param-case
parse-bmfont-ascii
parse-bmfont-binary
parse-bmfont-xml
parse-headers
parse-json
path-exists
path-is-absolute
path-parse
path-starts-with
path-type
peek-readable
performance-now
phin
pify
pify
pinkie-promise
pinkie
pixelmatch
pngjs
pngjs
prebuild-install
prettier-bytes
printj
prismjs
process-nextick-args
process
promise-retry
proto-list
pseudomap
psl
pump
punycode
punycode
qs
qs
query-string
queue-tick
queue
quick-lru
rc
read-pkg-up
read-pkg
readable-stream
readable-stream
readable-stream
readable-web-to-node-stream
readdir-glob
redent
regenerator-runtime
relateurl
repeating
request
require-directory
resolve-alpn
resolve
responselike
retry-request
retry
retry
rimraf
rimraf
safe-buffer
safe-buffer
safer-buffer
sax
select2
semver
semver
semver
semver
setimmediate
sha.js
sharp
side-channel
sigmund
signal-exit
simple-concat
simple-get
simple-swizzle
sindresorhus/is
slug
smithy/abort-controller
smithy/chunked-blob-reader-native
smithy/chunked-blob-reader
smithy/config-resolver
smithy/credential-provider-imds
smithy/eventstream-codec
smithy/eventstream-serde-browser
smithy/eventstream-serde-config-resolver
smithy/eventstream-serde-node
smithy/eventstream-serde-universal
smithy/fetch-http-handler
smithy/hash-blob-browser
smithy/hash-node
smithy/hash-stream-node
smithy/invalid-dependency
smithy/is-array-buffer
smithy/md5-js
smithy/middleware-content-length
smithy/middleware-endpoint
smithy/middleware-retry
smithy/middleware-serde
smithy/middleware-stack
smithy/node-config-provider
smithy/node-http-handler
smithy/property-provider
smithy/protocol-http
smithy/querystring-builder
smithy/querystring-parser
smithy/service-error-classification
smithy/shared-ini-file-loader
smithy/signature-v4
smithy/smithy-client
smithy/types
smithy/url-parser
smithy/util-base64
smithy/util-body-length-browser
smithy/util-body-length-node
smithy/util-buffer-from
smithy/util-config-provider
smithy/util-defaults-mode-browser
smithy/util-defaults-mode-node
smithy/util-endpoints
smithy/util-hex-encoding
smithy/util-middleware
smithy/util-retry
smithy/util-stream
smithy/util-uri-escape
smithy/util-utf8
smithy/util-waiter
sortablejs
source-map
spdx-correct
spdx-exceptions
spdx-expression-parse
spdx-license-ids
split-on-first
sqlstring
ssh2-sftp-client
ssh2
sshpk
status-logger
stream-consume
stream-events
stream-shift
streamx
strict-uri-encode
string-width
string-width
string_decoder
string_decoder
string_decoder
strip-ansi
strip-ansi
strip-bom
strip-indent
strip-json-comments
striptags
strnum
strtok3
stubs
szmarczak/http-timer
tabler-icons
tar-fs
tar-fs
tar-stream
tar-stream
teeny-request
through2
timm
tinycolor2
tinycolorpicker
tinymce
token-types
tokenizer/token
tootallnate/once
tough-cookie
tr46
transliteration
tree-flatten
trim-newlines
tslib
tslib
tunnel-agent
tweetnacl
typedarray
types/cacheable-request
types/codemirror
types/estree
types/http-cache-semantics
types/keyv
types/marked
types/node
types/node
types/responselike
types/tern
typo-js
uglify-js
unescape
unicode
universalify
unzip-crx-3
upper-case
uri-js
utif2
util-deprecate
uuid
uuid
uuid
validate-npm-package-license
verror
vue-color
vue-i18n
vue-multiselect
vue-prism-editor
vue-router
vue
vuedraggable
vuex
webidl-conversions
whatwg-fetch
whatwg-url
wordwrap
wrap-ansi
wrap-ansi
wrappy
xcase
xhr
xml-parse-from-string
xml2js
xmlbuilder
xregexp
xtend
y18n
yaku
yallist
yallist
yargs-parser
yargs
yocto-queue
zip-stream

These dependencies, which the developers have little or no control over, have already and will continue to cause problems (see here, here, here, here, here, here, here and here for example). I don't know what the long term plans are, but if the developers intend on sticking with this approach, they're making a big mistake in my opinion. These "apps" that ride on Electron and other such frameworks, often lack a native look and feel and fail to provide the expected functionality on any platform. For example, Publii ignores any native spelling dictionaries, nor can you add words to the built-in one. The developers would do well to read Using a framework can make you stupid!, To framework or not to framework?, So-called modern web developers are the culprits, and How to write software that will keep working for decades without problems.

the verdict

I have tested a sizable bunch of CMS/SSG software which i thought might meet my needs and which included, or could potentially accommodate a proper visual editor, among them automad, bludit, cmsimple, craftercms, datenstrom, dokuwiki, flatpress, flextype, foswiki, guppy, htmly, lnblog, monocms, mozilo, pluxml, typesetter and wondercms. In the end none of them really grabbed me and though Publii currently has many issues, i found it to be better suited to my needs overall given my preferences and fun-flow ('cause writing usually isn't work), plus the off-line, desktop installable aspect was a big sell.

One of my worries is that the developers seem unusually resistant to addressing some of the bugs, annoyances and reasonable feature requests. For example there's no reason whatsoever to have the post title consume as much screen real estate as it does in the editor, yet the suggestion to size it down, or move it to the sidebar, was flatly denied.

Even though Publii is far from being considered stable, their interaction with the community is somewhat sporadic which seems odd for such a young and ambitious project with no shortage of issues, more than 250 as of this writing and they seem to keep piling up. For example there are quite a few issues both on the forum and the code repository which were never answered, passed off as trivial, or given the "wontfix" label. The developers seem to be more concerned with adding features than fixing the most basic problems, like not being able to configure Piblii's data directory, etc..

Overall Publii is very usable as it is but a lot more work is certainly needed and, if the extreme dependency on 3rd party software continues, it will never be a proper product in my opinion. If you're wanting to build a simple, static website without all the worries and headaches of databases and plug-ins and whatnot, i wouldn't let the negatives stop you from giving it a spin, and surely some of the current bugs will be addressed at some point. I would also say that it's unlikely you'll experience all of the problems i have since i used it to convert this website from a ClassicPress affair (WordPress without the "block" editor) using an HTML backup rather than an XML export and this required a significant amount of work and a rather long shell script.

All that said, i'm not sure Publii will survive. While the concept of the project and effort of the developers is greatly appreciated, the way they're handling it flawed in my opinion. I was even chastised by Bob Mitro, one of the two developers, who essentially suggested i fuck off and fork Publii after i had submitted more bug reports than he cared to deal with. Although it can be disappointing to learn of bugs in the code i write, i have always gone to any length necessary to fix them rather than act like a dickhead, and i gained a degree of satisfaction in the process knowing that my code was a bit more robust.

Setting aside the possibility that Publii may go belii-up at some point, i think it's a project that's well-worth checking out, though primarily because it's pretty much the only project of its type at the moment. Hopefully someone will take Bob's advice, fork Publii, and be more appreciative of those providing feedback. Relying on piles of 3rd party code that they can't fix is a mistake in my opinion.