203 lines
9.8 KiB
Nix
203 lines
9.8 KiB
Nix
{ pkgs, google-chrome, symlinkJoin, stdenv, elmPackages, libjpeg, optipng, pngquant, ... }:
|
|
|
|
let
|
|
pnpm2nix = pkgs.callPackage (builtins.fetchGit {
|
|
url = "https://github.com/notgne2/pnpm2nix.git";
|
|
rev = "909accd35d23664254b43109ee58cd0c3d83a6d9";
|
|
}) {};
|
|
|
|
nodeCleanSourceFilter = name: type: pkgs.lib.cleanSourceFilter name type &&
|
|
((baseNameOf name) != "node_modules");
|
|
nodeCleanSource = src: pkgs.lib.cleanSourceWith { filter = nodeCleanSourceFilter; inherit src; };
|
|
|
|
elmCleanSourceFilter = name: type: nodeCleanSourceFilter name type &&
|
|
((baseNameOf name) != "elm-stuff" && (baseNameOf name) != "dist");
|
|
elmCleanSource = src: pkgs.lib.cleanSourceWith { filter = elmCleanSourceFilter; inherit src; };
|
|
|
|
scrapeNodeDeps = nodePkg:
|
|
let
|
|
nodeDeps = (builtins.filter (x: builtins.hasAttr "nodejs" x) nodePkg.buildInputs);
|
|
in
|
|
pkgs.lib.unique (nodeDeps ++ builtins.concatLists (map scrapeNodeDeps nodeDeps));
|
|
|
|
findNodeDep = nodePkg: name:
|
|
(builtins.elemAt 0 (builtins.filter (x: x.pname == name) (scrapeNodeDeps nodePkg)));
|
|
|
|
builderPkg = pnpm2nix.mkPnpmPackage {
|
|
name = "builder-node-packages";
|
|
packageJSON = ./package.json;
|
|
pnpmLock = ./pnpm-lock.yaml;
|
|
src = nodeCleanSource ./.;
|
|
overrides = pnpm2nix.defaultPnpmOverrides // {
|
|
puppeteer = (drv: drv.overrideAttrs(oldAttrs: {
|
|
preBuild = ''
|
|
# Define the local chromium directory
|
|
local_chromium=$HOME/node_modules/puppeteer/.local-chromium/linux-686378
|
|
# Make sure that directory exists
|
|
mkdir -p $local_chromium
|
|
# Link pkgs' standard google chrome into place
|
|
cp -r --no-preserve=mode,ownership ${google-chrome}/share/google/chrome $local_chromium/chrome-linux
|
|
cp ${google-chrome}/bin/google-chrome-stable $local_chromium/chrome-linux/chrome
|
|
chmod +x $local_chromium/chrome-linux/chrome
|
|
'';
|
|
}));
|
|
imagemin-pngquant = (drv: drv.overrideAttrs(oldAttrs: {
|
|
buildInputs = oldAttrs.buildInputs ++ [ pkgs.libpng ];
|
|
}));
|
|
pngquant-bin = (drv: drv.overrideAttrs(oldAttrs: {
|
|
preBuild = ''
|
|
mkdir -p $HOME/node_modules/pngquant-bin/vendor
|
|
ln -s ${pngquant}/bin/pngquant $HOME/node_modules/pngquant-bin/vendor/pngquant
|
|
'';
|
|
}));
|
|
|
|
gifsicle = (drv: drv.overrideAttrs(oldAttrs: {
|
|
buildInputs = oldAttrs.buildInputs ++ [ pkgs.autoconf pkgs.automake ];
|
|
}));
|
|
|
|
optipng = (drv: drv.overrideAttrs(oldAttrs: {
|
|
buildInputs = [ optipng ];
|
|
}));
|
|
optipng-bin = (drv: drv.overrideAttrs(oldAttrs: {
|
|
preBuild = ''
|
|
mkdir -p $HOME/node_modules/optipng-bin/vendor
|
|
ln -s ${optipng}/bin/optipng $HOME/node_modules/optipng-bin/vendor/optipng
|
|
'';
|
|
}));
|
|
|
|
jpegtran = (drv: drv.overrideAttrs(oldAttrs: {
|
|
buildInputs = [ libjpeg ];
|
|
}));
|
|
jpegtran-bin = (drv: drv.overrideAttrs(oldAttrs: {
|
|
preBuild = ''
|
|
mkdir -p $HOME/node_modules/jpegtran-bin/vendor
|
|
ln -s ${libjpeg}/bin/jpegtran $HOME/node_modules/jpegtran-bin/vendor/jpegtran
|
|
'';
|
|
}));
|
|
};
|
|
};
|
|
|
|
mkWandardFront = {
|
|
name,
|
|
prettyName ? name,
|
|
description ? "",
|
|
themeColor ? "#000000",
|
|
backgroundColor ? "#000000",
|
|
src,
|
|
nodePackages ? null,
|
|
routes ? [ "/" ],
|
|
}:
|
|
let
|
|
nodeSource = symlinkJoin {
|
|
name = "${name}-node-sources";
|
|
paths = [
|
|
builderPkg.lib
|
|
] ++ (if nodePackages != null then [ nodePackages ] else [ ]);
|
|
};
|
|
|
|
baseWebpackConfig = builtins.readFile ./webpack.config.js;
|
|
webpackConfig = ''
|
|
const ROUTES = ${builtins.toJSON routes}
|
|
const PRETTY_NAME = ${builtins.toJSON prettyName}
|
|
const DESCRIPTION = ${builtins.toJSON description}
|
|
const THEME_COLOR = ${builtins.toJSON themeColor}
|
|
const BACKGROUND_COLOR = ${builtins.toJSON backgroundColor}
|
|
'' + "\n" + baseWebpackConfig;
|
|
webpackConfigFile = pkgs.writeText "${name}-webpack-config" webpackConfig;
|
|
|
|
wandInit = pkgs.writeText "wand.js" ''
|
|
document.body.innerHTML = '''
|
|
const sourceTarget = document.createElement('script')
|
|
sourceTarget.src = '/main.js'
|
|
document.body.appendChild(sourceTarget)
|
|
|
|
if ('serviceWorker' in navigator) {
|
|
window.addEventListener('load', () => navigator.serviceWorker.register('/sw.js'));
|
|
}
|
|
'';
|
|
|
|
templateHtml = pkgs.writeText "template-html" ''
|
|
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta http-equiv="Content-type" content="text/html; charset=utf-8"/>
|
|
<title><%= htmlWebpackPlugin.options.title %></title>
|
|
<link rel="apple-touch-icon" sizes="57x57" href="/appdata/apple-touch-icon-57x57.png">
|
|
<link rel="apple-touch-icon" sizes="60x60" href="/appdata/apple-touch-icon-60x60.png">
|
|
<link rel="apple-touch-icon" sizes="72x72" href="/appdata/apple-touch-icon-72x72.png">
|
|
<link rel="apple-touch-icon" sizes="76x76" href="/appdata/apple-touch-icon-76x76.png">
|
|
<link rel="apple-touch-icon" sizes="114x114" href="/appdata/apple-touch-icon-114x114.png">
|
|
<link rel="apple-touch-icon" sizes="120x120" href="/appdata/apple-touch-icon-120x120.png">
|
|
<link rel="apple-touch-icon" sizes="144x144" href="/appdata/apple-touch-icon-144x144.png">
|
|
<link rel="apple-touch-icon" sizes="152x152" href="/appdata/apple-touch-icon-152x152.png">
|
|
<link rel="apple-touch-icon" sizes="167x167" href="/appdata/apple-touch-icon-167x167.png">
|
|
<link rel="apple-touch-icon" sizes="180x180" href="/appdata/apple-touch-icon-180x180.png">
|
|
<link rel="apple-touch-icon" sizes="1024x1024" href="/appdata/apple-touch-icon-1024x1024.png">
|
|
<link rel="apple-touch-startup-image" media="(device-width: 320px) and (device-height: 480px) and (-webkit-device-pixel-ratio: 1)" href="/appdata/apple-touch-startup-image-320x460.png">
|
|
<link rel="apple-touch-startup-image" media="(device-width: 320px) and (device-height: 480px) and (-webkit-device-pixel-ratio: 2)" href="/appdata/apple-touch-startup-image-640x920.png">
|
|
<link rel="apple-touch-startup-image" media="(device-width: 320px) and (device-height: 568px) and (-webkit-device-pixel-ratio: 2)" href="/appdata/apple-touch-startup-image-640x1096.png">
|
|
<link rel="apple-touch-startup-image" media="(device-width: 375px) and (device-height: 667px) and (-webkit-device-pixel-ratio: 2)" href="/appdata/apple-touch-startup-image-750x1294.png">
|
|
<link rel="apple-touch-startup-image" media="(device-width: 414px) and (device-height: 736px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 3)" href="/appdata/apple-touch-startup-image-1182x2208.png">
|
|
<link rel="apple-touch-startup-image" media="(device-width: 414px) and (device-height: 736px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 3)" href="/appdata/apple-touch-startup-image-1242x2148.png">
|
|
<link rel="apple-touch-startup-image" media="(device-width: 768px) and (device-height: 1024px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 1)" href="/appdata/apple-touch-startup-image-748x1024.png">
|
|
<link rel="apple-touch-startup-image" media="(device-width: 768px) and (device-height: 1024px) and (orientation: landscape) and (-webkit-device-pixel-ratio: 2)" href="/appdata/apple-touch-startup-image-1496x2048.png">
|
|
<link rel="apple-touch-startup-image" media="(device-width: 768px) and (device-height: 1024px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 1)" href="/appdata/apple-touch-startup-image-768x1004.png">
|
|
<link rel="apple-touch-startup-image" media="(device-width: 768px) and (device-height: 1024px) and (orientation: portrait) and (-webkit-device-pixel-ratio: 2)" href="/appdata/apple-touch-startup-image-1536x2008.png">
|
|
<link rel="icon" type="image/png" sizes="16x16" href="/appdata/favicon-16x16.png">
|
|
<link rel="icon" type="image/png" sizes="32x32" href="/appdata/favicon-32x32.png">
|
|
<link rel="icon" type="image/png" sizes="228x228" href="/appdata/coast-228x228.png">
|
|
<link rel="manifest" href="/appdata/manifest.json">
|
|
<link rel="shortcut icon" href="/appdata/favicon.ico">
|
|
<link rel="yandex-tableau-widget" href="/appdata/yandex-browser-manifest.json">
|
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
|
<meta name="apple-mobile-web-app-title">
|
|
<meta name="application-name" content="${prettyName}">
|
|
<meta name="mobile-web-app-capable" content="yes">
|
|
<meta name="msapplication-TileColor" content="#fff">
|
|
<meta name="msapplication-TileImage" content="/appdata/mstile-144x144.png">
|
|
<meta name="msapplication-config" content="/appdata/browserconfig.xml">
|
|
<meta name="theme-color" content="${themeColor}">
|
|
</head>
|
|
<body>
|
|
</body>
|
|
</html>
|
|
'';
|
|
in
|
|
stdenv.mkDerivation {
|
|
inherit name;
|
|
|
|
src = elmCleanSource src;
|
|
|
|
buildInputs = with elmPackages; [
|
|
elm
|
|
elm-format
|
|
nodeSource
|
|
];
|
|
|
|
patchPhase = ''
|
|
ln -sf ${nodeSource}/node_modules .
|
|
cp ${webpackConfigFile} webpack.config.js
|
|
cp ${wandInit} wand.js
|
|
cp ${templateHtml} template.html
|
|
'';
|
|
|
|
shellHook = ''
|
|
ln -sf ${nodeSource}/node_modules .
|
|
'';
|
|
|
|
buildPhase = elmPackages.fetchElmDeps {
|
|
elmPackages = import (src + "/elm-srcs.nix");
|
|
versionsDat = src + "/versions.dat";
|
|
};
|
|
|
|
installPhase = ''
|
|
mkdir -p $out
|
|
${nodeSource}/node_modules/webpack-cli/bin/cli.js --mode production
|
|
mv dist/* $out
|
|
'';
|
|
};
|
|
in
|
|
{
|
|
inherit mkWandardFront;
|
|
} |