Initial Commit

This commit is contained in:
Anthony Cicchetti 2021-12-22 13:05:51 -05:00
commit 39ba6d5a48
23 changed files with 22430 additions and 0 deletions

18
.config/dotnet-tools.json Normal file
View file

@ -0,0 +1,18 @@
{
"version": 1,
"isRoot": true,
"tools": {
"fable": {
"version": "3.6.2",
"commands": [
"fable"
]
},
"femto": {
"version": "0.12.0",
"commands": [
"femto"
]
}
}
}

63
.gitattributes vendored Normal file
View file

@ -0,0 +1,63 @@
###############################################################################
# Set default behavior to automatically normalize line endings.
###############################################################################
* text=auto
###############################################################################
# Set default behavior for command prompt diff.
#
# This is need for earlier builds of msysgit that does not have it on by
# default for csharp files.
# Note: This is only used by command line
###############################################################################
#*.cs diff=csharp
###############################################################################
# Set the merge driver for project and solution files
#
# Merging from the command prompt will add diff markers to the files if there
# are conflicts (Merging from VS is not affected by the settings below, in VS
# the diff markers are never inserted). Diff markers may cause the following
# file extensions to fail to load in VS. An alternative would be to treat
# these files as binary and thus will always conflict and require user
# intervention with every merge. To do so, just uncomment the entries below
###############################################################################
#*.sln merge=binary
#*.csproj merge=binary
#*.vbproj merge=binary
#*.vcxproj merge=binary
#*.vcproj merge=binary
#*.dbproj merge=binary
#*.fsproj merge=binary
#*.lsproj merge=binary
#*.wixproj merge=binary
#*.modelproj merge=binary
#*.sqlproj merge=binary
#*.wwaproj merge=binary
###############################################################################
# behavior for image files
#
# image files are treated as binary by default.
###############################################################################
#*.jpg binary
#*.png binary
#*.gif binary
###############################################################################
# diff behavior for common document formats
#
# Convert binary document formats to text before diffing them. This feature
# is only available from the command line. Turn it on by uncommenting the
# entries below.
###############################################################################
#*.doc diff=astextplain
#*.DOC diff=astextplain
#*.docx diff=astextplain
#*.DOCX diff=astextplain
#*.dot diff=astextplain
#*.DOT diff=astextplain
#*.pdf diff=astextplain
#*.PDF diff=astextplain
#*.rtf diff=astextplain
#*.RTF diff=astextplain

206
.gitignore vendored Normal file
View file

@ -0,0 +1,206 @@
public/bundle.js*
# Node
node_modules/
## Ignore Visual Studio temporary files, build results, and
## files generated by popular Visual Studio add-ons.
# User-specific files
*.suo
*.user
*.sln.docstates
# Xamarin Studio / monodevelop user-specific
*.userprefs
*.dll.mdb
*.exe.mdb
tests-js
deploy
# Build results
[Dd]ebug/
[Rr]elease/
x64/
[Bb]in/
[Oo]bj/
# MSTest test Results
[Tt]est[Rr]esult*/
[Bb]uild[Ll]og.*
*_i.c
*_p.c
*.ilk
*.meta
*.obj
*.pch
*.pdb
*.pgc
*.pgd
*.rsp
*.sbr
*.tlb
*.tli
*.tlh
*.tmp
*.tmp_proj
*.log
*.vspscc
*.vssscc
.builds
*.pidb
*.log
*.scc
# Visual C++ cache files
ipch/
*.aps
*.ncb
*.opensdf
*.sdf
*.cachefile
# Visual Studio profiler
*.psess
*.vsp
*.vspx
# Other Visual Studio data
.vs/
# Guidance Automation Toolkit
*.gpState
# ReSharper is a .NET coding add-in
_ReSharper*/
*.[Rr]e[Ss]harper
# TeamCity is a build add-in
_TeamCity*
# DotCover is a Code Coverage Tool
*.dotCover
# NCrunch
*.ncrunch*
.*crunch*.local.xml
# Installshield output folder
#[Ee]xpress/
# DocProject is a documentation generator add-in
DocProject/buildhelp/
DocProject/Help/*.HxT
DocProject/Help/*.HxC
DocProject/Help/*.hhc
DocProject/Help/*.hhk
DocProject/Help/*.hhp
DocProject/Help/Html2
DocProject/Help/html
# Click-Once directory
publish/
# Publish Web Output
*.Publish.xml
# Enable nuget.exe in the .nuget folder (though normally executables are not tracked)
!.nuget/NuGet.exe
# Windows Azure Build Output
csx
*.build.csdef
# Windows Store app package directory
AppPackages/
# Others
sql/
*.Cache
ClientBin/
[Ss]tyle[Cc]op.*
~$*
*~
*.dbmdl
*.[Pp]ublish.xml
*.pfx
*.publishsettings
# RIA/Silverlight projects
Generated_Code/
# Backup & report files from converting an old project file to a newer
# Visual Studio version. Backup files are not needed, because we have git ;-)
_UpgradeReport_Files/
Backup*/
UpgradeLog*.XML
UpgradeLog*.htm
# SQL Server files
App_Data/*.mdf
App_Data/*.ldf
#LightSwitch generated files
GeneratedArtifacts/
_Pvt_Extensions/
ModelManifest.xml
# =========================
# Windows detritus
# =========================
# Windows image file caches
Thumbs.db
ehthumbs.db
# Folder config file
Desktop.ini
# Recycle Bin used on file shares
$RECYCLE.BIN/
# Mac desktop service store files
.DS_Store
# ===================================================
# Exclude F# project specific directories and files
# ===================================================
# NuGet Packages Directory
packages/
# Generated documentation folder
docs/output/
# Temp folder used for publishing docs
temp*/
# Test results produced by build
TestResults.xml
TestResult.xml
# Nuget outputs
nuget/*.nupkg
release.cmd
release.sh
localpackages/
paket-files
*.orig
docs/content/license.md
docs/content/release-notes.md
.fake
docs/tools/FSharp.Formatting.svclog
.ionide.debug
*.bak
project.lock.json
deploy/
obj
bin
out
.fable
.vs
.ionide
*.fs.js
*.fs.js.map

44
App.sln Normal file
View file

@ -0,0 +1,44 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.29418.71
MinimumVisualStudioVersion = 10.0.40219.1
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "App", "src\App.fsproj", "{E5DEFC96-37CF-4844-9C9E-CFA0A9A8AED3}"
EndProject
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "Tests", "tests\Tests.fsproj", "{7821B727-268F-44AD-8136-B300B323F578}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{BACD6DDA-A974-47EC-813A-4C76682A4536}"
ProjectSection(SolutionItems) = preProject
.gitattributes = .gitattributes
.gitignore = .gitignore
.config\dotnet-tools.json = .config\dotnet-tools.json
NuGet.Config = NuGet.Config
package-lock.json = package-lock.json
package.json = package.json
README.md = README.md
webpack.common.js = webpack.common.js
webpack.config.js = webpack.config.js
webpack.tests.js = webpack.tests.js
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{E5DEFC96-37CF-4844-9C9E-CFA0A9A8AED3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E5DEFC96-37CF-4844-9C9E-CFA0A9A8AED3}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E5DEFC96-37CF-4844-9C9E-CFA0A9A8AED3}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E5DEFC96-37CF-4844-9C9E-CFA0A9A8AED3}.Release|Any CPU.Build.0 = Release|Any CPU
{7821B727-268F-44AD-8136-B300B323F578}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7821B727-268F-44AD-8136-B300B323F578}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7821B727-268F-44AD-8136-B300B323F578}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7821B727-268F-44AD-8136-B300B323F578}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {10E8CD24-3EC2-4B88-AF25-F5807B4B92B9}
EndGlobalSection
EndGlobal

10
NuGet.Config Normal file
View file

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<packageSources>
<clear/>
<add key="NuGet.org" value="https://api.nuget.org/v3/index.json"/>
</packageSources>
<disabledPackageSources>
<clear/>
</disabledPackageSources>
</configuration>

55
README.md Normal file
View file

@ -0,0 +1,55 @@
# Feliz Template
This template gets you up and running with a simple web app using [Fable](http://fable.io/)
, [Elmish](https://fable-elmish.github.io/) and [Feliz](https://github.com/Zaid-Ajaj/Feliz).
## Requirements
* [dotnet SDK](https://www.microsoft.com/net/download/core) 2.0.0 or higher
* [node.js](https://nodejs.org) 10.0.0 or higher
## Editor
To write and edit your code, you can use either VS Code + [Ionide](http://ionide.io/), Emacs
with [fsharp-mode](https://github.com/fsharp/emacs-fsharp-mode), [Rider](https://www.jetbrains.com/rider/) or Visual
Studio.
## Development
Before doing anything, start with installing npm dependencies using `npm install`.
Then to start development mode with hot module reloading, run:
```bash
npm start
```
This will start the development server after compiling the project, once it is finished, navigate
to http://localhost:8080 to view the application .
To build the application and make ready for production:
```
npm run build
```
This command builds the application and puts the generated files into the `deploy` directory (can be overwritten in
webpack.config.js).
### Tests
The template includes a test project that ready to go which you can either run in the browser in watch mode or run in
the console using node.js and mocha. To run the tests in watch mode:
```
npm run test:live
```
This command starts a development server for the test application and makes it available at http://localhost:8085.
To run the tests using the command line and of course in your CI server, you have to use the mocha test runner which
doesn't use the browser but instead runs the code using node.js:
```
npm test
```

21412
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

46
package.json Normal file
View file

@ -0,0 +1,46 @@
{
"private": true,
"scripts": {
"prestart": "dotnet tool restore",
"start": "dotnet fable watch ./src -s --run webpack-dev-server",
"prebuild": "dotnet tool restore",
"build": "dotnet fable ./src && webpack",
"test:live": "dotnet fable watch tests --run webpack-dev-server --config ./webpack.tests.js",
"build:test": "dotnet fable tests && webpack --config webpack.tests.js",
"pretest": "dotnet tool restore",
"test": "dotnet fable tests --outDir dist/tests && mocha dist/tests -r esm"
},
"dependencies": {
"date-fns": "^2.16.1",
"react": "^17.0.1",
"react-dom": "^17.0.1"
},
"devDependencies": {
"@babel/core": "^7.12.10",
"@babel/preset-env": "^7.12.11",
"@babel/preset-react": "^7.12.10",
"@babel/runtime": "^7.12.5",
"@pmmmwh/react-refresh-webpack-plugin": "^0.4.3",
"babel-loader": "^8.2.2",
"copy-webpack-plugin": "^6.4.1",
"core-js": "^3.8.2",
"css-loader": "^5.0.1",
"dotenv-webpack": "^6.0.0",
"esm": "^3.2.25",
"file-loader": "^6.2.0",
"graceful-fs": "^4.2.4",
"html-webpack-plugin": "^4.5.1",
"mini-css-extract-plugin": "^1.3.4",
"mocha": "^8.2.1",
"react-refresh": "^0.9.0",
"sass": "^1.32.4",
"sass-loader": "^10.1.1",
"source-map-loader": "^2.0.1",
"style-loader": "^2.0.0",
"tailwindcss": "^3.0.7",
"terser": "^4.8.0",
"webpack": "^4.44.2",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.2"
}
}

5
src/Actions.fs Normal file
View file

@ -0,0 +1,5 @@
module App.Actions
open System
type Msg = ChangeDate of DateTime

22
src/App.fsproj Normal file
View file

@ -0,0 +1,22 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<None Include="index.html" />
<Compile Include="Extensions.fs" />
<Compile Include="Actions.fs" />
<Compile Include="DatePicker.fs" />
<Compile Include="UserEntry.fs" />
<Compile Include="Container.fs" />
<Compile Include="Main.fs" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Fable.Fetch" Version="2.4.0" />
<PackageReference Include="Feliz" Version="1.57.0" />
<PackageReference Include="Feliz.Router" Version="3.8.0" />
<PackageReference Include="Fable.DateFunctions" Version="3.8.1" />
<PackageReference Include="Thoth.Json" Version="6.0.0" />
<PackageReference Include="Zanaptak.TypedCssClasses" Version="1.0.0" />
</ItemGroup>
</Project>

21
src/Container.fs Normal file
View file

@ -0,0 +1,21 @@
module App.Container
open System
open Actions
open Feliz
type State = { Date: DateTime }
let initialState = { Date = DateTime.Now }
let update (state: State) =
function
| Msg.ChangeDate dateTime -> { state with Date = dateTime }
[<ReactComponent>]
let Container () =
let (state, dispatch) = React.useReducer (update, initialState)
Html.div [ DatePicker.DatePicker(state.Date, dispatch)
Html.ol [ UserEntry.UserEntry("a_mae_zing", state.Date)
UserEntry.UserEntry("Anthony", state.Date) ] ]

13
src/DatePicker.fs Normal file
View file

@ -0,0 +1,13 @@
module App.DatePicker
open System
open App.Actions
open Feliz
type formattedString = string
[<ReactComponent>]
let DatePicker (currentDate: DateTime, updateDate) =
Html.input [ prop.type'.date
prop.value currentDate
prop.onChange (fun (newValue: DateTime) -> updateDate (Msg.ChangeDate(newValue))) ]

40
src/Extensions.fs Normal file
View file

@ -0,0 +1,40 @@
[<AutoOpen>]
module Extensions
open System
open Fable.Core
open Fable.Core.JsInterop
[<RequireQualifiedAccess>]
module StaticFile =
/// Function that imports a static file by it's relative path.
let inline import (path: string) : string = importDefault<string> path
[<RequireQualifiedAccess>]
module Config =
/// Returns the value of a configured variable using its key.
/// Retursn empty string when the value does not exist
[<Emit("process.env[$0] ? process.env[$0] : ''")>]
let variable (key: string) : string = jsNative
/// Tries to find the value of the configured variable if it is defined or returns a given default value otherwise.
let variableOrDefault (key: string) (defaultValue: string) =
let foundValue = variable key
if String.IsNullOrWhiteSpace foundValue then
defaultValue
else
foundValue
/// Stylesheet API
/// let private stylehsheet = Stylesheet.load "./fancy.module.css"
/// stylesheet.["fancy-class-name"] which returns a string
module Stylesheet =
type IStylesheet =
[<Emit "$0[$1]">]
abstract Item : className: string -> string
/// Loads a CSS module and makes the classes within available
let inline load (path: string) = importDefault<IStylesheet> path

11
src/Main.fs Normal file
View file

@ -0,0 +1,11 @@
module Main
open System
open Feliz
open App
open Browser.Dom
open Fable.Core.JsInterop
importSideEffects "./styles/global.scss"
ReactDOM.render (Container.Container(), document.getElementById "feliz-app")

77
src/UserEntry.fs Normal file
View file

@ -0,0 +1,77 @@
module UserEntry
open System
open Feliz
open Fable.DateFunctions
open Fetch
open Thoth.Json
type State =
| LoadingScore
| ErrorFetchingScore
| LoadedScore of string
| NoScore
type Score = { Name: string; Time: string }
type ScoreApiResponse = Score list
let GetUserScore (scores: Score list) (username: string) =
scores
|> List.tryFind (fun u -> u.Name = username)
|> function
| Some (x) -> LoadedScore(x.Time)
| None -> NoScore
[<ReactComponent>]
let UserEntry (username: string, currentDate: DateTime) =
let (score, setScore) = React.useState (LoadingScore)
let load () =
async {
printfn $"Current Date == {currentDate}"
fetch $"""https://acicchetti.dev/crossword/v1/{currentDate.Format "YYYY-MM-DD"}""" []
|> Promise.bind (fun res -> res.text ())
|> Promise.map
(fun txt ->
let decoded =
Decode.Auto.fromString<ScoreApiResponse> (txt, caseStrategy = CamelCase)
match decoded with
| Ok (apiResponse) ->
printfn $"""got {apiResponse}"""
let score = GetUserScore apiResponse username
setScore (score)
| Error (_) -> setScore (ErrorFetchingScore))
|> ignore
}
React.useEffect
(fun () ->
printfn $"Current Date == {currentDate}"
fetch $"""https://acicchetti.dev/crossword/v1/{currentDate.Format "yyyy-MM-dd"}""" []
|> Promise.bind (fun res -> res.text ())
|> Promise.map
(fun txt ->
let decoded =
Decode.Auto.fromString<ScoreApiResponse> (txt, caseStrategy = CamelCase)
match decoded with
| Ok (apiResponse) ->
printfn $"""got {apiResponse}"""
let score = GetUserScore apiResponse username
setScore (score)
| Error (_) -> setScore (ErrorFetchingScore))
|> ignore),
[| box currentDate |]
Html.article [ props.className
Html.h1 [ prop.text
$"""{username} - {match score with
| LoadingScore -> "Loading"
| ErrorFetchingScore -> "Error Fetching Score"
| LoadedScore s -> s
| NoScore -> "No Score"}""" ] ]

16
src/index.html Normal file
View file

@ -0,0 +1,16 @@
<!doctype html>
<html>
<head>
<title>Feliz App</title>
<meta http-equiv='Content-Type' content='text/html; charset=utf-8'>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="shortcut icon" type="image/png" href="img/favicon-32x32.png"
sizes="32x32"/>
<link rel="shortcut icon" type="image/png" href="img/favicon-16x16.png"
sizes="16x16"/>
<script src="https://cdn.polyfill.io/v2/polyfill.js?features=es6"></script>
</head>
<body>
<div id="feliz-app"></div>
</body>
</html>

0
src/styles/global.scss Normal file
View file

18
tests/Tests.fs Normal file
View file

@ -0,0 +1,18 @@
module Tests
open Fable.Mocha
let add x y = x + y
let appTests =
testList
"App tests"
[ testCase "add works"
<| fun _ ->
let result = add 2 3
Expect.equal result 5 "Result must be 5" ]
let allTests = testList "All" [ appTests ]
[<EntryPoint>]
let main (args: string []) = Mocha.runTests allTests

14
tests/Tests.fsproj Normal file
View file

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net5.0</TargetFramework>
</PropertyGroup>
<ItemGroup>
<Compile Include="Tests.fs"/>
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\src\App.fsproj"/>
</ItemGroup>
<ItemGroup>
<PackageReference Include="Fable.Mocha" Version="2.9.1"/>
</ItemGroup>
</Project>

9
tests/index.html Normal file
View file

@ -0,0 +1,9 @@
<!DOCTYPE html>
<html>
<head>
<title>Feliz tests</title>
</head>
<body>
</body>
</html>

9
webpack.common.js Normal file
View file

@ -0,0 +1,9 @@
// common utilities used by webpack
var realFs = require('fs')
var gracefulFs = require('graceful-fs')
module.exports = {
// Patches the fs native module with the alternative graceful-fs module
// which handles EMFILE errors internally
patchGracefulFileSystem: () => gracefulFs.gracefulify(realFs)
}

163
webpack.config.js Normal file
View file

@ -0,0 +1,163 @@
// Template for webpack.config.js in Fable projects
// In most cases, you'll only need to edit the CONFIG object (after dependencies)
// See below if you need better fine-tuning of Webpack options
var path = require("path");
var HtmlWebpackPlugin = require('html-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var MiniCssExtractPlugin = require("mini-css-extract-plugin");
const ReactRefreshWebpackPlugin = require('@pmmmwh/react-refresh-webpack-plugin');
const Dotenv = require('dotenv-webpack');
const {patchGracefulFileSystem} = require("./webpack.common.js");
patchGracefulFileSystem();
// If we're running the webpack-dev-server, assume we're in development mode
var isProduction = !process.argv.find(v => v.indexOf('webpack-dev-server') !== -1);
const isDevelopment = !isProduction && process.env.NODE_ENV !== 'production';
var CONFIG = {
// The tags to include the generated JS and CSS will be automatically injected in the HTML template
// See https://github.com/jantimon/html-webpack-plugin
indexHtmlTemplate: "./src/index.html",
fsharpEntry: "./src/Main.fs.js",
outputDir: "./dist",
assetsDir: "./public",
devServerPort: 8080,
// When using webpack-dev-server, you may need to redirect some calls
// to a external API server. See https://webpack.js.org/configuration/dev-server/#devserver-proxy
devServerProxy: {
'/api/*': {
// assuming the backend is running on port 5000
target: "http://localhost:5000",
changeOrigin: true
}
},
// Use babel-preset-env to generate JS compatible with most-used browsers.
// More info at https://babeljs.io/docs/en/next/babel-preset-env.html
babel: {
plugins: [isDevelopment && require.resolve('react-refresh/babel')].filter(Boolean),
presets: ["@babel/preset-env", "@babel/preset-react"]
}
}
console.log("Bundling for " + (isProduction ? "production" : "development") + "...");
// The HtmlWebpackPlugin allows us to use a template for the index.html page
// and automatically injects <script> or <link> tags for generated bundles.
var commonPlugins = [
new HtmlWebpackPlugin({
filename: 'index.html',
template: resolve(CONFIG.indexHtmlTemplate)
}),
new Dotenv({
path: "./.env",
silent: false,
systemvars: true
})
];
module.exports = {
// In development, bundle styles together with the code so they can also
// trigger hot reloads. In production, put them in a separate CSS file.
entry: {
app: [resolve(CONFIG.fsharpEntry)]
},
// Add a hash to the output file name in production
// to prevent browser caching if code changes
output: {
path: resolve(CONFIG.outputDir),
filename: isProduction ? '[name].[hash].js' : '[name].js'
},
mode: isProduction ? "production" : "development",
devtool: isProduction ? "source-map" : "eval-source-map",
optimization: {
// Split the code coming from npm packages into a different file.
// 3rd party dependencies change less often, let the browser cache them.
splitChunks: {
cacheGroups: {
commons: {
test: /node_modules/,
name: "vendors",
chunks: "all"
}
}
},
},
// Besides the HtmlPlugin, we use the following plugins:
// PRODUCTION
// - MiniCssExtractPlugin: Extracts CSS from bundle to a different file
// To minify CSS, see https://github.com/webpack-contrib/mini-css-extract-plugin#minimizing-for-production
// - CopyWebpackPlugin: Copies static assets to output directory
// DEVELOPMENT
// - HotModuleReplacementPlugin: Enables hot reloading when code changes without refreshing
plugins: isProduction ?
commonPlugins.concat([
new MiniCssExtractPlugin({filename: 'style.[contenthash].css'}),
new CopyWebpackPlugin({
patterns: [
{from: resolve(CONFIG.assetsDir)}
]
}),
])
: commonPlugins.concat([
new ReactRefreshWebpackPlugin()
]),
resolve: {
// See https://github.com/fable-compiler/Fable/issues/1490
symlinks: false,
modules: [resolve("./node_modules")],
alias: {
// Some old libraries still use an old specific version of core-js
// Redirect the imports of these libraries to the newer core-js
'core-js/es6': 'core-js/es'
}
},
// Configuration for webpack-dev-server
devServer: {
publicPath: "/",
contentBase: resolve(CONFIG.assetsDir),
port: CONFIG.devServerPort,
proxy: CONFIG.devServerProxy,
hot: true,
inline: true
},
// - babel-loader: transforms JS to old syntax (compatible with old browsers)
// - sass-loaders: transforms SASS/SCSS into JS
// - file-loader: Moves files referenced in the code (fonts, images) into output folder
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: CONFIG.babel
},
},
{
test: /\.(sass|scss|css)$/,
use: [
isProduction
? MiniCssExtractPlugin.loader
: 'style-loader',
{
loader: 'css-loader',
},
{
loader: 'sass-loader',
options: {implementation: require("sass")}
}
],
},
{
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)(\?.*)?$/,
use: ["file-loader"]
}
]
}
};
function resolve(filePath) {
return path.isAbsolute(filePath) ? filePath : path.join(__dirname, filePath);
}

158
webpack.tests.js Normal file
View file

@ -0,0 +1,158 @@
// Template for webpack.config.js in Fable projects
// In most cases, you'll only need to edit the CONFIG object (after dependencies)
// See below if you need better fine-tuning of Webpack options
// Dependencies. Also required: core-js, @babel/core,
// @babel/preset-env, babel-loader
var path = require("path");
var webpack = require("webpack");
var HtmlWebpackPlugin = require('html-webpack-plugin');
var CopyWebpackPlugin = require('copy-webpack-plugin');
var MiniCssExtractPlugin = require("mini-css-extract-plugin");
const Dotenv = require('dotenv-webpack');
const {patchGracefulFileSystem} = require("./webpack.common.js");
patchGracefulFileSystem();
module.exports = (env, argv) => {
const isProduction = argv.mode === 'production'
const isDevelopment = argv.mode === 'development'
console.log("Bundling for " + (isProduction ? "production" : "development") + "...");
var CONFIG = {
// The tags to include the generated JS and CSS will be automatically injected in the HTML template
// See https://github.com/jantimon/html-webpack-plugin
indexHtmlTemplate: "./tests/index.html",
fsharpEntry: "./tests/Tests.fs.js",
outputDir: "./dist",
assetsDir: "./public",
devServerPort: 8085,
// When using webpack-dev-server, you may need to redirect some calls
// to a external API server. See https://webpack.js.org/configuration/dev-server/#devserver-proxy
devServerProxy: undefined,
// Use babel-preset-env to generate JS compatible with most-used browsers.
// More info at https://babeljs.io/docs/en/next/babel-preset-env.html
babel: {
presets: [
// In case interop is used with React/Jsx components, this React preset would be required
["@babel/preset-react"],
["@babel/preset-env", {
"targets": "> 0.25%, not dead",
"modules": false,
// This adds polyfills when needed. Requires core-js dependency.
// See https://babeljs.io/docs/en/babel-preset-env#usebuiltins
"useBuiltIns": "usage",
"corejs": 3
}]
],
}
}
// The HtmlWebpackPlugin allows us to use a template for the index.html page
// and automatically injects <script> or <link> tags for generated bundles.
var commonPlugins = [
new HtmlWebpackPlugin({
filename: 'index.html',
template: resolve(CONFIG.indexHtmlTemplate)
}),
new Dotenv({
path: "./.env",
silent: false,
systemvars: true
})
];
return {
// In development, bundle styles together with the code so they can also
// trigger hot reloads. In production, put them in a separate CSS file.
entry: {
app: [resolve(CONFIG.fsharpEntry)]
},
// Add a hash to the output file name in production
// to prevent browser caching if code changes
output: {
path: resolve(CONFIG.outputDir),
filename: isProduction ? '[name].[contenthash].js' : '[name].js'
},
devtool: isProduction ? "source-map" : "eval-source-map",
optimization: {
// Split the code coming from npm packages into a different file.
// 3rd party dependencies change less often, let the browser cache them.
splitChunks: {
cacheGroups: {
commons: {
test: /node_modules/,
name: "vendors",
chunks: "all"
}
}
},
},
plugins: commonPlugins.concat([
new CopyWebpackPlugin({
patterns: [
{from: resolve(CONFIG.assetsDir)}
]
}),
]),
resolve: {
// See https://github.com/fable-compiler/Fable/issues/1490
symlinks: false,
modules: [resolve("./node_modules")],
alias: {
// Some old libraries still use an old specific version of core-js
// Redirect the imports of these libraries to the newer core-js
'core-js/es6': 'core-js/es'
}
},
// Configuration for webpack-dev-server
devServer: {
publicPath: "/",
contentBase: resolve(CONFIG.assetsDir),
port: CONFIG.devServerPort,
proxy: CONFIG.devServerProxy,
hot: true,
inline: true
},
// - fable-loader: transforms F# into JS
// - babel-loader: transforms JS to old syntax (compatible with old browsers)
// - sass-loaders: transforms SASS/SCSS into JS
// - file-loader: Moves files referenced in the code (fonts, images) into output folder
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: CONFIG.babel
}
},
{
test: /\.(sass|scss|css)$/,
use: [
isProduction
? MiniCssExtractPlugin.loader
: 'style-loader',
{
loader: 'css-loader'
},
{
loader: 'sass-loader',
options: {implementation: require("sass")}
}
],
},
{
test: /\.(png|jpg|jpeg|gif|svg|woff|woff2|ttf|eot)(\?.*)?$/,
use: ["file-loader"]
}
]
}
}
};
function resolve(filePath) {
return path.isAbsolute(filePath) ? filePath : path.join(__dirname, filePath);
}