From 80770301395c741500fc8a3097ef44dc97bf1372 Mon Sep 17 00:00:00 2001 From: Rok Garbas Date: Sat, 28 Mar 2020 05:09:01 +0100 Subject: [PATCH] intial version of elm+webpack setup --- .gitignore | 33 ++++ default.nix | 25 +++ elm.json | 31 +++ package.json | 45 +++++ scripts/import-channels-into-elasticsearch | 7 +- src/Main.elm | 216 +++++++++++++++++++++ src/assets/.gitkeep | 0 src/assets/images/.gitkeep | 0 src/assets/images/logo.png | Bin 0 -> 7822 bytes src/index.html | 11 ++ src/index.js | 15 ++ src/styles.scss | 30 +++ tests/Example.elm | 52 +++++ webpack.config.js | 185 ++++++++++++++++++ 14 files changed, 648 insertions(+), 2 deletions(-) create mode 100644 .gitignore create mode 100644 default.nix create mode 100644 elm.json create mode 100644 package.json create mode 100644 src/Main.elm create mode 100644 src/assets/.gitkeep create mode 100644 src/assets/images/.gitkeep create mode 100644 src/assets/images/logo.png create mode 100644 src/index.html create mode 100644 src/index.js create mode 100644 src/styles.scss create mode 100644 tests/Example.elm create mode 100644 webpack.config.js diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7b35590 --- /dev/null +++ b/.gitignore @@ -0,0 +1,33 @@ +# Logs +logs +*.log +.idea +.cache +npm-debug.log* + + +# Compiled binary addons (http://nodejs.org/api/addons.html) +build/Release + +# Dependency directory +node_modules + +# Optional npm cache directory +.npm +yarn.lock + +# Optional REPL history +.node_repl_history + +# elm-package generated files +elm-stuff/ +# elm-repl generated files +repl-temp-* + +.DS_Store +example/dist + +ignore +dist +tests/VerifyExamples +package-lock.json diff --git a/default.nix b/default.nix new file mode 100644 index 0000000..d8aba6f --- /dev/null +++ b/default.nix @@ -0,0 +1,25 @@ +{ pkgs ? import {} +}: + +let +in pkgs.stdenv.mkDerivation { + name = "nixos-search"; + src = pkgs.lib.cleanSource ./.; + + buildInputs = + (with pkgs; [ + nodejs + ]) ++ + (with pkgs.nodePackages; [ + yarn + ]) ++ + (with pkgs.elmPackages; [ + elm + elm-format + ]); + + shellHook = '' + export PATH=$PWD/node_modules/.bin:$PATH + ''; + +} diff --git a/elm.json b/elm.json new file mode 100644 index 0000000..019388f --- /dev/null +++ b/elm.json @@ -0,0 +1,31 @@ +{ + "type": "application", + "source-directories": [ + "src" + ], + "elm-version": "0.19.1", + "dependencies": { + "direct": { + "elm/browser": "1.0.2", + "elm/core": "1.0.4", + "elm/html": "1.0.0", + "elm/http": "2.0.0", + "elm/json": "1.1.3", + "elm/url": "1.0.0" + }, + "indirect": { + "elm/bytes": "1.0.8", + "elm/file": "1.0.5", + "elm/time": "1.0.0", + "elm/virtual-dom": "1.0.2" + } + }, + "test-dependencies": { + "direct": { + "elm-explorations/test": "1.2.2" + }, + "indirect": { + "elm/random": "1.0.0" + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..e7fc97e --- /dev/null +++ b/package.json @@ -0,0 +1,45 @@ +{ + "name": "nixos-search", + "version": "1.0.0", + "description": "Search NixOS packages and options.", + "main": "index.js", + "repository": "https://github.com/NixOS/nixos-search", + "author": "Rok Garbas ", + "license": "MIT", + "scripts": { + "test": "elm-test", + "dev": "webpack-dev-server --hot --colors --port 3000", + "build": "webpack", + "prod": "webpack -p", + "analyse": "elm-analyse -s -p 3001 -o" + }, + "devDependencies": { + "@babel/core": "^7.7.2", + "@babel/preset-env": "^7.7.1", + "babel-loader": "^8.0.6", + "clean-webpack-plugin": "^3.0.0", + "closure-webpack-plugin": "^2.0.1", + "copy-webpack-plugin": "^5.0.5", + "css-loader": "^3.2.0", + "elm-analyse": "^0.16.5", + "elm-hot-webpack-loader": "^1.1.6", + "elm-test": "^0.19.1-1", + "elm-webpack-loader": "^6.0.1", + "file-loader": "^6.0.0", + "google-closure-compiler": "^20200224.0.0", + "html-webpack-plugin": "^4.0.2", + "mini-css-extract-plugin": "^0.9.0", + "node-sass": "^4.13.1", + "resolve-url-loader": "^3.1.0", + "sass-loader": "^8.0.0", + "style-loader": "^1.0.0", + "url-loader": "^4.0.0", + "webpack": "^4.41.2", + "webpack-cli": "^3.3.10", + "webpack-dev-server": "^3.9.0", + "webpack-merge": "^4.2.2" + }, + "dependencies": { + "purecss": "^1.0.1" + } +} diff --git a/scripts/import-channels-into-elasticsearch b/scripts/import-channels-into-elasticsearch index 23a31bf..2243fc7 100755 --- a/scripts/import-channels-into-elasticsearch +++ b/scripts/import-channels-into-elasticsearch @@ -27,13 +27,16 @@ def get_last_evaluation(channel): ) evaluations = [] for item in s3_result.get("CommonPrefixes"): - if not item : + if not item: continue prefix = item.get("Prefix") evaluation = prefix[len(f"{project}/{project_version}/{channel}"):] if evaluation.startswith("beta"): evaluation = evaluation[len("beta"):] - revisions_since_start, git_revision = evaluation.lstrip(".").rstrip("/").split(".") + try: + revisions_since_start, git_revision = evaluation.lstrip(".").rstrip("/").split(".") + except: + continue evaluations.append(dict( revisions_since_start=int(revisions_since_start), git_revision=git_revision, diff --git a/src/Main.elm b/src/Main.elm new file mode 100644 index 0000000..7c44a96 --- /dev/null +++ b/src/Main.elm @@ -0,0 +1,216 @@ +port module Main exposing (main) + +import Browser exposing (UrlRequest(..)) +import Browser.Navigation as Nav exposing (Key) +import Html exposing (..) +import Html.Attributes exposing (..) +import Html.Events exposing (onClick) +import Http exposing (Error(..)) +import Json.Decode as Decode +import Url exposing (Url) +import Url.Parser as UrlParser exposing ((), Parser) + + + +-- --------------------------- +-- PORTS +-- --------------------------- + + +port toJs : String -> Cmd msg + + + +-- --------------------------- +-- MODEL +-- --------------------------- + + +type alias Model = + { key : Key + , page : Page + } + + +init : Int -> Url -> Key -> ( Model, Cmd Msg ) +init flags url key = + ( { key = key, page = UrlParser.parse urlParser url |> Maybe.withDefault (Counter 0) }, Cmd.none ) + + +type Page + = Counter Int + | Server String + + + +-- --------------------------- +-- URL Parsing and Routing +-- --------------------------- + + +handleUrlRequest : Key -> UrlRequest -> Cmd msg +handleUrlRequest key urlRequest = + case urlRequest of + Internal url -> + Nav.pushUrl key (Url.toString url) + + External url -> + Nav.load url + + +urlParser : Parser (Page -> msg) msg +urlParser = + UrlParser.oneOf + [ UrlParser.map Counter <| UrlParser.s "counter" UrlParser.int + , UrlParser.map Server <| UrlParser.s "server" UrlParser.string + , UrlParser.map (Server "") <| UrlParser.s "server" + ] + + + +-- --------------------------- +-- UPDATE +-- --------------------------- + + +type Msg + = OnUrlRequest UrlRequest + | OnUrlChange Url + | Inc + | TestServer + | OnServerResponse (Result Http.Error String) + + +update : Msg -> Model -> ( Model, Cmd Msg ) +update message model = + case message of + OnUrlRequest urlRequest -> + ( model, handleUrlRequest model.key urlRequest ) + + OnUrlChange url -> + ( { model | page = UrlParser.parse urlParser url |> Maybe.withDefault model.page }, Cmd.none ) + + Inc -> + case model.page of + Counter x -> + let + xx = + x + 1 + in + ( { model | page = Counter xx } + , Nav.pushUrl model.key <| "/counter/" ++ String.fromInt xx + ) + + _ -> + ( model, Cmd.none ) + + TestServer -> + let + expect = + Http.expectJson OnServerResponse (Decode.field "result" Decode.string) + in + ( model + , Http.get { url = "/test", expect = expect } + ) + + OnServerResponse res -> + case res of + Ok serverMessage -> + ( { model | page = Server serverMessage }, Cmd.none ) + + Err err -> + ( { model | page = Server <| "Error: " ++ httpErrorToString err }, Cmd.none ) + + +httpErrorToString : Http.Error -> String +httpErrorToString err = + case err of + BadUrl _ -> + "BadUrl" + + Timeout -> + "Timeout" + + NetworkError -> + "NetworkError" + + BadStatus _ -> + "BadStatus" + + BadBody s -> + "BadBody: " ++ s + + + +-- --------------------------- +-- VIEW +-- --------------------------- + + +view : Model -> Html Msg +view model = + div [ class "container" ] + [ header [] + [ img [ src "/images/logo.png" ] [] + , h1 [] [ text "Elm 0.19 Webpack Starter, with hot-reloading" ] + ] + , case model.page of + Counter counter -> + counterPage counter + + Server serverMessage -> + serverPage serverMessage + , p [] + [ text "And now don't forget to add a star to the Github repo " + , a [ href "https://github.com/simonh1000/elm-webpack-starter" ] [ text "elm-webpack-starter" ] + ] + ] + + +counterPage counter = + div [ class "pure-u-1-3" ] + [ a [ href "/server/" ] [ text "Switch to server" ] + , p [] [ text "Click on the button below to increment the state." ] + , button + [ class "pure-button pure-button-primary" + , onClick Inc + ] + [ text "+ 1" ] + , text <| String.fromInt counter + , p [] [ text "Then make a change to the source code and see how the state is retained after you recompile." ] + ] + + +serverPage serverMessage = + div [ class "pure-u-1-3" ] + [ a [ href "/counter/1" ] [ text "Switch to counter" ] + , p [] [ text "Test the dev server" ] + , button + [ class "pure-button pure-button-primary" + , onClick TestServer + ] + [ text "ping dev server" ] + , text serverMessage + ] + + + +-- --------------------------- +-- MAIN +-- --------------------------- + + +main : Program Int Model Msg +main = + Browser.application + { init = init + , update = update + , view = + \m -> + { title = "Elm 0.19 starter" + , body = [ view m ] + } + , subscriptions = \_ -> Sub.none + , onUrlRequest = OnUrlRequest + , onUrlChange = OnUrlChange + } diff --git a/src/assets/.gitkeep b/src/assets/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/assets/images/.gitkeep b/src/assets/images/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/src/assets/images/logo.png b/src/assets/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..dcb019cb18bc57f94d87e88f0cf5a0d1134dd093 GIT binary patch literal 7822 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 K>X+*|MgAYvB4ld- literal 0 HcmV?d00001 diff --git a/src/index.html b/src/index.html new file mode 100644 index 0000000..b78bafd --- /dev/null +++ b/src/index.html @@ -0,0 +1,11 @@ + + + + + + Elm hotloading dev environment + + + + + diff --git a/src/index.js b/src/index.js new file mode 100644 index 0000000..7a86b21 --- /dev/null +++ b/src/index.js @@ -0,0 +1,15 @@ +'use strict'; + +require("./styles.scss"); + +const {Elm} = require('./Main'); +var app = Elm.Main.init({flags: 6}); + +app.ports.toJs.subscribe(data => { + console.log(data); +}) +// Use ES2015 syntax and let Babel compile it for you +var testFn = (inp) => { + let a = inp + 1; + return a; +} diff --git a/src/styles.scss b/src/styles.scss new file mode 100644 index 0000000..32b3611 --- /dev/null +++ b/src/styles.scss @@ -0,0 +1,30 @@ +@import '~purecss/build/pure.css'; + +body { + background-color: #ddd; + margin-top: 20px; +} +.container { + max-width: 800px; + margin-left: auto; + margin-right: auto; +} +header { + display: flex; + align-items: center; + img { + width: 60px; + margin-right: 30px; + } +} + +button { + margin-right: 15px; +} + +.logo { + background: url('images/logo.png'); + width: 60px; + height: 60px; + background-size: cover; +} diff --git a/tests/Example.elm b/tests/Example.elm new file mode 100644 index 0000000..1bcd7b0 --- /dev/null +++ b/tests/Example.elm @@ -0,0 +1,52 @@ +module Example exposing (fuzzTest, unitTest, viewTest) + +import Expect exposing (Expectation) +import Fuzz exposing (Fuzzer, int, list, string) +import Main exposing (..) +import Test exposing (..) +import Test.Html.Query as Query +import Test.Html.Selector exposing (tag, text) + + +{-| See +-} +unitTest : Test +unitTest = + describe "simple unit test" + [ test "Inc adds one" <| + \() -> + update Inc (Model 0 "") + |> Tuple.first + |> .counter + |> Expect.equal 1 + ] + + +{-| See +-} +fuzzTest : Test +fuzzTest = + describe "simple fuzz test" + [ fuzz int "Inc ALWAYS adds one" <| + \ct -> + update Inc (Model ct "") + |> Tuple.first + |> .counter + |> Expect.equal (ct + 1) + ] + + +{-| see +-} +viewTest : Test +viewTest = + describe "Testing view function" + [ test "Button has the expected text" <| + \() -> + Model 0 "" + |> view + |> Query.fromHtml + |> Query.findAll [ tag "button" ] + |> Query.first + |> Query.has [ text "+ 1" ] + ] diff --git a/webpack.config.js b/webpack.config.js new file mode 100644 index 0000000..e87f41c --- /dev/null +++ b/webpack.config.js @@ -0,0 +1,185 @@ +const path = require("path"); +const webpack = require("webpack"); +const merge = require("webpack-merge"); + +const ClosurePlugin = require('closure-webpack-plugin'); +const CopyWebpackPlugin = require("copy-webpack-plugin"); +const HTMLWebpackPlugin = require("html-webpack-plugin"); +const { CleanWebpackPlugin } = require('clean-webpack-plugin'); +// to extract the css as a separate file +const MiniCssExtractPlugin = require("mini-css-extract-plugin"); + +var MODE = + process.env.npm_lifecycle_event === "prod" ? "production" : "development"; +var withDebug = !process.env["npm_config_nodebug"] && MODE == "development"; +// this may help for Yarn users +// var withDebug = !npmParams.includes("--nodebug"); +console.log('\x1b[36m%s\x1b[0m', `** elm-webpack-starter: mode "${MODE}", withDebug: ${withDebug}\n`); + +var common = { + mode: MODE, + entry: "./src/index.js", + output: { + path: path.join(__dirname, "dist"), + publicPath: "/", + // FIXME webpack -p automatically adds hash when building for production + filename: MODE == "production" ? "[name]-[hash].js" : "index.js" + }, + plugins: [ + new HTMLWebpackPlugin({ + // Use this template to get basic responsive meta tags + template: "src/index.html", + // inject details of output file at end of body + inject: "body" + }) + ], + resolve: { + modules: [path.join(__dirname, "src"), "node_modules"], + extensions: [".js", ".elm", ".scss", ".png"] + }, + module: { + rules: [ + { + test: /\.js$/, + exclude: /node_modules/, + use: { + loader: "babel-loader" + } + }, + { + test: /\.scss$/, + exclude: [/elm-stuff/, /node_modules/], + // see https://github.com/webpack-contrib/css-loader#url + loaders: ["style-loader", "css-loader?url=false", "sass-loader"] + }, + { + test: /\.css$/, + exclude: [/elm-stuff/, /node_modules/], + loaders: ["style-loader", "css-loader?url=false"] + }, + { + test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, + exclude: [/elm-stuff/, /node_modules/], + loader: "url-loader", + options: { + limit: 10000, + mimetype: "application/font-woff" + } + }, + { + test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, + exclude: [/elm-stuff/, /node_modules/], + loader: "file-loader" + }, + { + test: /\.(jpe?g|png|gif|svg)$/i, + exclude: [/elm-stuff/, /node_modules/], + loader: "file-loader" + } + ] + } +}; + +if (MODE === "development") { + module.exports = merge(common, { + plugins: [ + // Suggested for hot-loading + new webpack.NamedModulesPlugin(), + // Prevents compilation errors causing the hot loader to lose state + new webpack.NoEmitOnErrorsPlugin() + ], + module: { + rules: [ + { + test: /\.elm$/, + exclude: [/elm-stuff/, /node_modules/], + use: [ + { loader: "elm-hot-webpack-loader" }, + { + loader: "elm-webpack-loader", + options: { + // add Elm's debug overlay to output + debug: withDebug, + // + forceWatch: true + } + } + ] + } + ] + }, + devServer: { + inline: true, + stats: "errors-only", + contentBase: path.join(__dirname, "src/assets"), + historyApiFallback: true, + // feel free to delete this section if you don't need anything like this + before(app) { + // on port 3000 + app.get("/test", function(req, res) { + res.json({ result: "OK" }); + }); + } + } + }); +} +if (MODE === "production") { + module.exports = merge(common, { + //optimization: { + // minimizer: [ + // new ClosurePlugin({mode: 'STANDARD'}, {}) + // ] + //}, + plugins: [ + // Delete everything from output-path (/dist) and report to user + new CleanWebpackPlugin({ + root: __dirname, + exclude: [], + verbose: true, + dry: false + }), + // Copy static assets + new CopyWebpackPlugin([ + { + from: "src/assets" + } + ]), + new MiniCssExtractPlugin({ + // Options similar to the same options in webpackOptions.output + // both options are optional + filename: "[name]-[hash].css" + }) + ], + module: { + rules: [ + { + test: /\.elm$/, + exclude: [/elm-stuff/, /node_modules/], + use: { + loader: "elm-webpack-loader", + options: { + optimize: true + } + } + }, + { + test: /\.css$/, + exclude: [/elm-stuff/, /node_modules/], + loaders: [ + MiniCssExtractPlugin.loader, + "css-loader?url=false" + ] + }, + { + test: /\.scss$/, + exclude: [/elm-stuff/, /node_modules/], + loaders: [ + MiniCssExtractPlugin.loader, + "css-loader?url=false", + "sass-loader" + ] + } + ] + } + }); +}