├── .gitignore ├── src ├── favicon.ico ├── static │ ├── img │ │ └── elm.jpg │ ├── styles │ │ └── main.scss │ ├── index.js │ └── index.html └── elm │ ├── Components │ └── Hello.elm │ └── Main.elm ├── elm-package.json ├── package.json ├── README.md └── webpack.config.js /.gitignore: -------------------------------------------------------------------------------- 1 | elm-stuff/ 2 | node_modules/ 3 | tmp/ 4 | dist/ 5 | yarn.lock 6 | 7 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elm-community/elm-webpack-starter/master/src/favicon.ico -------------------------------------------------------------------------------- /src/static/img/elm.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/elm-community/elm-webpack-starter/master/src/static/img/elm.jpg -------------------------------------------------------------------------------- /src/static/styles/main.scss: -------------------------------------------------------------------------------- 1 | $icon-font-path: '~bootstrap-sass/assets/fonts/bootstrap/'; 2 | @import '~bootstrap-sass/assets/stylesheets/bootstrap/_mixins.scss'; 3 | @import '~bootstrap-sass/assets/stylesheets/_bootstrap.scss'; 4 | 5 | // can add Boostrap overrides, additional Sass/CSS below... 6 | -------------------------------------------------------------------------------- /src/elm/Components/Hello.elm: -------------------------------------------------------------------------------- 1 | module Components.Hello exposing (..) 2 | 3 | import Html exposing (..) 4 | import Html.Attributes exposing (..) 5 | import String 6 | 7 | -- hello component 8 | hello : Int -> Html a 9 | hello model = 10 | div 11 | [ class "h1" ] 12 | [ text ( "Hello, Elm" ++ ( "!" |> String.repeat model ) ) ] 13 | -------------------------------------------------------------------------------- /src/static/index.js: -------------------------------------------------------------------------------- 1 | // pull in desired CSS/SASS files 2 | require( './styles/main.scss' ); 3 | var $ = jQuery = require( '../../node_modules/jquery/dist/jquery.js' ); // <--- remove if jQuery not needed 4 | require( '../../node_modules/bootstrap-sass/assets/javascripts/bootstrap.js' ); // <--- remove if Bootstrap's JS not needed 5 | 6 | // inject bundled Elm app into div#main 7 | var Elm = require( '../elm/Main' ); 8 | Elm.Main.embed( document.getElementById( 'main' ) ); 9 | -------------------------------------------------------------------------------- /src/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | elm-webpack-starter 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | -------------------------------------------------------------------------------- /elm-package.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "1.0.0", 3 | "summary": "Example using `elm-webpack-loader`.", 4 | "repository": "https://github.com/moarwick/elm-webpack-starter.git", 5 | "license": "MIT", 6 | "source-directories": [ 7 | "src/elm" 8 | ], 9 | "exposed-modules": [], 10 | "dependencies": { 11 | "elm-lang/core": "5.0.0 <= v < 6.0.0", 12 | "elm-lang/html": "2.0.0 <= v < 3.0.0", 13 | "elm-lang/http": "1.0.0 <= v < 2.0.0", 14 | "evancz/elm-markdown": "3.0.1 <= v < 4.0.0" 15 | }, 16 | "elm-version": "0.18.0 <= v < 0.19.0" 17 | } 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "elm-webpack-starter", 3 | "description": "Webpack setup for writing Elm apps", 4 | "version": "0.8.6", 5 | "license": "MIT", 6 | "author": "Peter Morawiec", 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/moarwick/elm-webpack-starter" 10 | }, 11 | "scripts": { 12 | "start": "webpack-dev-server --hot --inline", 13 | "prebuild": "rimraf dist", 14 | "build": "webpack", 15 | "reinstall": "npm i rimraf && rimraf node_modules && npm uninstall -g elm && npm i -g elm && npm i && elm package install" 16 | }, 17 | "devDependencies": { 18 | "autoprefixer": "^6.7.7", 19 | "bootstrap-sass": "^3.3.7", 20 | "copy-webpack-plugin": "^4.0.1", 21 | "css-loader": "^0.27.3", 22 | "elm": "^0.18.0", 23 | "elm-webpack-loader": "^4.3.0", 24 | "extract-text-webpack-plugin": "^2.1.0", 25 | "file-loader": "^0.10.1", 26 | "html-webpack-plugin": "^2.28.0", 27 | "jquery": "^3.2.1", 28 | "node-sass": "^4.5.1", 29 | "postcss-loader": "^1.3.3", 30 | "rimraf": "^2.6.1", 31 | "sass-loader": "^6.0.3", 32 | "style-loader": "^0.16.0", 33 | "url-loader": "^0.5.8", 34 | "webpack": "^2.3.1", 35 | "webpack-dev-server": "^2.4.2", 36 | "webpack-merge": "^4.1.0" 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/elm/Main.elm: -------------------------------------------------------------------------------- 1 | module Main exposing (..) 2 | import Html exposing (..) 3 | import Html.Attributes exposing (..) 4 | import Html.Events exposing ( onClick ) 5 | 6 | -- component import example 7 | import Components.Hello exposing ( hello ) 8 | 9 | 10 | -- APP 11 | main : Program Never Model Msg 12 | main = 13 | Html.beginnerProgram { model = model, view = view, update = update } 14 | 15 | 16 | -- MODEL 17 | type alias Model = Int 18 | 19 | model : Model 20 | model = 0 21 | 22 | 23 | -- UPDATE 24 | type Msg = NoOp | Increment 25 | 26 | update : Msg -> Model -> Model 27 | update msg model = 28 | case msg of 29 | NoOp -> model 30 | Increment -> model + 1 31 | 32 | 33 | -- VIEW 34 | -- Html is defined as: elem [ attribs ][ children ] 35 | -- CSS can be applied via class names or inline style attrib 36 | view : Model -> Html Msg 37 | view model = 38 | div [ class "container", style [("margin-top", "30px"), ( "text-align", "center" )] ][ -- inline CSS (literal) 39 | div [ class "row" ][ 40 | div [ class "col-xs-12" ][ 41 | div [ class "jumbotron" ][ 42 | img [ src "static/img/elm.jpg", style styles.img ] [] -- inline CSS (via var) 43 | , hello model -- ext 'hello' component (takes 'model' as arg) 44 | , p [] [ text ( "Elm Webpack Starter" ) ] 45 | , button [ class "btn btn-primary btn-lg", onClick Increment ] [ -- click handler 46 | span[ class "glyphicon glyphicon-star" ][] -- glyphicon 47 | , span[][ text "FTW!" ] 48 | ] 49 | ] 50 | ] 51 | ] 52 | ] 53 | 54 | 55 | -- CSS STYLES 56 | styles : { img : List ( String, String ) } 57 | styles = 58 | { 59 | img = 60 | [ ( "width", "33%" ) 61 | , ( "border", "4px solid #337AB7") 62 | ] 63 | } 64 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # elm-webpack-starter 2 | 3 | 4 | ### About: 5 | A simple Webpack setup for writing [Elm](http://elm-lang.org/) apps: 6 | 7 | * Dev server with live reloading, HMR 8 | * Support for CSS/SCSS (with Autoprefixer), image assets 9 | * Bootstrap 3.3+ (Sass version) 10 | * Bundling and minification for deployment 11 | * Basic app scaffold, using `Html.beginnerProgram` 12 | * A snippet of example code to get you started! 13 | 14 | 15 | ### Install: 16 | Clone this repo into a new project folder, e.g. `my-elm-project`: 17 | ``` 18 | git clone https://github.com/moarwick/elm-webpack-starter my-elm-project 19 | cd my-elm-project 20 | ``` 21 | 22 | Re-initialize the project folder as your own repo: 23 | ``` 24 | rm -rf .git # on Windows: rmdir .git /s /q 25 | git init 26 | git add . 27 | git commit -m 'first commit' 28 | ``` 29 | 30 | Install all dependencies using the handy `reinstall` script: 31 | ``` 32 | npm run reinstall 33 | ``` 34 | *This does a clean (re)install of all npm and elm packages, plus a global elm install.* 35 | 36 | 37 | ### Serve locally: 38 | ``` 39 | npm start 40 | ``` 41 | * Access app at `http://localhost:8080/` 42 | * Get coding! The entry point file is `src/elm/Main.elm` 43 | * Browser will refresh automatically on any file changes.. 44 | 45 | 46 | ### Build & bundle for prod: 47 | ``` 48 | npm run build 49 | ``` 50 | 51 | * Files are saved into the `/dist` folder 52 | * To check it, open `dist/index.html` 53 | 54 | 55 | ### Changelog 56 | 57 | **Ver 0.8.6** 58 | * Update Packages (-> Webpack 2) 59 | * fix paths in file-loader 60 | * clean up build script 61 | 62 | **Ver 0.8.5** 63 | * Fix loading path of generated js file, per [Issue 47](https://github.com/moarwick/elm-webpack-starter/issues/47) 64 | 65 | **Ver 0.8.4** 66 | * Fix hot reloading of components, per [Issue 44](https://github.com/moarwick/elm-webpack-starter/issues/44) 67 | 68 | **Ver 0.8.3** 69 | * Update packages 70 | * Attempt to fix path issues when building for prod (temp) 71 | 72 | **Ver 0.8.2** 73 | * Webpack config improvements (PR by [Lesuk](https://github.com/moarwick/elm-webpack-starter/pull/39)) 74 | 75 | **Ver 0.8.0** 76 | * Update to Elm 0.18, use `debug=true` on webpack loader (PR by [douglascorrea](https://github.com/moarwick/elm-webpack-starter/pull/33)) 77 | * Add a script for one-step installs 78 | * Update to latest packages 79 | 80 | **Ver 0.7.1** 81 | * Fix favicon issues, per [Issue 30](https://github.com/moarwick/elm-webpack-starter/issues/30) 82 | 83 | **Ver 0.7.0** 84 | * Modify project structure, per [Issue 26](https://github.com/moarwick/elm-webpack-starter/issues/26) 85 | * Include Bootstrap JS, per [Issue 28](https://github.com/moarwick/elm-webpack-starter/issues/28) 86 | * More helpful install steps in README, per [Issue 29](https://github.com/moarwick/elm-webpack-starter/issues/29) 87 | * Update to latest packages 88 | 89 | **Ver 0.6.2** 90 | * Use `copy-webpack-plugin` instead of `cp` to copy files (Windows compatible) 91 | 92 | **Ver 0.6.0** 93 | * `elm-hot-loader` is back (no Elm code changes required!) 94 | * Switch to [bootstrap-sass](https://www.npmjs.com/package/bootstrap-sass) to demo CSS 95 | 96 | **Ver 0.5.0** 97 | * Update to Elm 0.17.0 (and other latest modules) 98 | * Upgrade starter code per [upgrade-docs](https://github.com/elm-lang/elm-platform/blob/master/upgrade-docs/0.17.md) 99 | * Remove `elm-hot-loader` (for now) 100 | 101 | **Ver 0.4.0** 102 | * Add [elm-hot-loader](https://github.com/fluxxu/elm-hot-loader) for HMR support (PR by [fluxxu](https://github.com/fluxxu)) 103 | 104 | **Ver 0.3.0** 105 | * Use `html-webpack-plugin` to generate `index.html` 106 | * Apply hash filenames for bundled JS and CSS (prevents caching) 107 | * Image and favicon assets copied to `dist/` 108 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | var merge = require('webpack-merge'); 4 | var HtmlWebpackPlugin = require('html-webpack-plugin'); 5 | var autoprefixer = require('autoprefixer'); 6 | var ExtractTextPlugin = require('extract-text-webpack-plugin'); 7 | var CopyWebpackPlugin = require('copy-webpack-plugin'); 8 | 9 | 10 | const prod = 'production'; 11 | const dev = 'development'; 12 | 13 | // determine build env 14 | const TARGET_ENV = process.env.npm_lifecycle_event === 'build' ? prod : dev; 15 | const isDev = TARGET_ENV == dev; 16 | const isProd = TARGET_ENV == prod; 17 | 18 | // entry and output path/filename variables 19 | const entryPath = path.join(__dirname, 'src/static/index.js'); 20 | const outputPath = path.join(__dirname, 'dist'); 21 | const outputFilename = isProd ? '[name]-[hash].js' : '[name].js' 22 | 23 | console.log('WEBPACK GO! Building for ' + TARGET_ENV); 24 | 25 | // common webpack config (valid for dev and prod) 26 | var commonConfig = { 27 | output: { 28 | path: outputPath, 29 | filename: `static/js/${outputFilename}`, 30 | }, 31 | resolve: { 32 | extensions: ['.js', '.elm'], 33 | modules: ['node_modules'] 34 | }, 35 | module: { 36 | noParse: /\.elm$/, 37 | rules: [{ 38 | test: /\.(eot|ttf|woff|woff2|svg)$/, 39 | use: 'file-loader?publicPath=../../&name=static/css/[hash].[ext]' 40 | }] 41 | }, 42 | plugins: [ 43 | new webpack.LoaderOptionsPlugin({ 44 | options: { 45 | postcss: [autoprefixer()] 46 | } 47 | }), 48 | new HtmlWebpackPlugin({ 49 | template: 'src/static/index.html', 50 | inject: 'body', 51 | filename: 'index.html' 52 | }) 53 | ] 54 | } 55 | 56 | // additional webpack settings for local env (when invoked by 'npm start') 57 | if (isDev === true) { 58 | module.exports = merge(commonConfig, { 59 | entry: [ 60 | 'webpack-dev-server/client?http://localhost:8080', 61 | entryPath 62 | ], 63 | devServer: { 64 | // serve index.html in place of 404 responses 65 | historyApiFallback: true, 66 | contentBase: './src', 67 | hot: true 68 | }, 69 | module: { 70 | rules: [{ 71 | test: /\.elm$/, 72 | exclude: [/elm-stuff/, /node_modules/], 73 | use: [{ 74 | loader: 'elm-webpack-loader', 75 | options: { 76 | verbose: true, 77 | warn: true, 78 | debug: true 79 | } 80 | }] 81 | },{ 82 | test: /\.sc?ss$/, 83 | use: ['style-loader', 'css-loader', 'postcss-loader', 'sass-loader'] 84 | }] 85 | } 86 | }); 87 | } 88 | 89 | // additional webpack settings for prod env (when invoked via 'npm run build') 90 | if (isProd === true) { 91 | module.exports = merge(commonConfig, { 92 | entry: entryPath, 93 | module: { 94 | rules: [{ 95 | test: /\.elm$/, 96 | exclude: [/elm-stuff/, /node_modules/], 97 | use: 'elm-webpack-loader' 98 | }, { 99 | test: /\.sc?ss$/, 100 | use: ExtractTextPlugin.extract({ 101 | fallback: 'style-loader', 102 | use: ['css-loader', 'postcss-loader', 'sass-loader'] 103 | }) 104 | }] 105 | }, 106 | plugins: [ 107 | new ExtractTextPlugin({ 108 | filename: 'static/css/[name]-[hash].css', 109 | allChunks: true, 110 | }), 111 | new CopyWebpackPlugin([{ 112 | from: 'src/static/img/', 113 | to: 'static/img/' 114 | }, { 115 | from: 'src/favicon.ico' 116 | }]), 117 | 118 | // extract CSS into a separate file 119 | // minify & mangle JS/CSS 120 | new webpack.optimize.UglifyJsPlugin({ 121 | minimize: true, 122 | compressor: { 123 | warnings: false 124 | } 125 | // mangle: true 126 | }) 127 | ] 128 | }); 129 | } 130 | --------------------------------------------------------------------------------