Fable icon indicating copy to clipboard operation
Fable copied to clipboard

Differentiating development and production builds from F# code

Open kentcb opened this issue 2 years ago • 15 comments

Description

I'm looking for a way to alter my Fable application depending on whether it is being used in a development or production context. In my case, I want to use a different service implementation during development, but another example might be including a debug page only in development builds.

Importantly, I need to ensure the development-only code is not bundled in the production build. Therefore, simple config parameters will not suffice.

I cannot find any documentation on how to achieve this, perhaps using compilation symbols (e.g. FABLE_COMPILER_DEVELOPMENT) or the likes. Any help appreciated.

kentcb avatar Aug 05 '22 09:08 kentcb

Hi @kentcb! We usually use the DEBUG symbol for these purposes. By default, Fable will use DEBUG for watch compilations but if necessary you can define your own symbols with --define or a configuration as with dotnet builds (e.g. -c Debug or -c Release).

For example, this is how it's used in Elmish.HMR so HMR is only activated in development builds: https://github.com/elmish/hmr/blob/a87be3c097237eea136312e3e3e6cc5c739e4b14/src/hmr.fs#L182-L187

Note: DEBUG being used in packages is a Fable-unique feature, given packages a compiled from sources too, it won't work in dotnet builds.

alfonsogarciacaro avatar Aug 05 '22 10:08 alfonsogarciacaro

Thanks @alfonsogarciacaro. Hmm, I had tried that and it looks like it will work from an IDE perspective (relevant code is dimmed), but Fable still bundles the code wrapped in #if DEBUG. Maybe there's something funky going on with our setup - I'll dig deeper and get back to you.

kentcb avatar Aug 06 '22 01:08 kentcb

@alfonsogarciacaro Yeah, I'm just not sure what's going on yet. I can see from the Fable compiler source how it chooses a configuration, can confirm from build output that it is indeed Release, my configurations look correct (Release only defines RELEASE, definitely not DEBUG symbol), but I'm ending up with my #if DEBUG code in the output anyway. I tried --no-cache but didn't help.

If I run with --verbose I see this in my output:

F# PROJECT: src\App.fsproj
    --define:TRACE
    --define:DEBUG
    --define:NET
    --define:NET6_0
    <snip>

But have not been able to figure out why DEBUG is being defined yet. Unfortunately, it's a little convoluted how we run Fable (you know) and I've not been able to just run it directly yet (getting errors for reasons I don't understand). So may pick this up Monday.

kentcb avatar Aug 06 '22 07:08 kentcb

Hello @kentcb,

How are you invoking Fable ?

  • If you are using Fable 3 can you please share the CLI invoked.
  • If you are using Fable 2 can you please share the CLI + webpack (or any bundler) configuration

Can you please check that you didn't set DEBUG configuration inside of your *.fsproj?

MangelMaxime avatar Aug 06 '22 08:08 MangelMaxime

Hi @MangelMaxime. It's Fable 3.7.11, invoked as:

dotnet fable C:\<redacted>\src -o C:\<redacted>\.build\web\fable --exclude FablePlugins --precompiledLib C:\<redacted>\.build\web\fable --noParallelTypeCheck -s --watch --watchDelay 500 --define <redacted>_PLATFORM_IS_WEB --run C:\<redacted>\node_modules\.bin\webpack-dev-server --config C:\<redacted>\webpack.config.js

Can you please check that you didn't set DEBUG configuration inside of your *.fsproj?

Yeah, definitely haven't done that. We do have a custom configuration, but I had also tried removing that and going with defaults (Debug/Release) to no avail. Unfortunately, got pulled onto higher urgency stuff for the next day or so, but will definitely getting back to this when I can.

kentcb avatar Aug 07 '22 23:08 kentcb

Sorry, totally screwed up that fable command in my haste. Will get back to you once production fires are out.

kentcb avatar Aug 08 '22 01:08 kentcb

Here is the corrected command:

dotnet fable C:\<redacted>\src -o C:\<redacted>\.build\web\fable --exclude FablePlugins --verbose --precompiledLib C:\<redacted>\.build\web\fable --noCache --define <redacted>_PLATFORM_IS_WEB --run C:\<redacted>\node_modules\.bin\webpack --config C:\<redacted>\webpack.config.js

kentcb avatar Aug 12 '22 02:08 kentcb

OK, got a chance to debug through and can see that the DEBUG symbol must be defined somewhere in one of our reference projects:

image

Will need to go through them one-by-one to find which is the culprit.

I don't think it's ideal that Fable behaves like this, but not sure if it's as simple as ignoring DEBUG symbol for production builds.

kentcb avatar Aug 12 '22 05:08 kentcb

OK, the project causing the issue is multi-targeting:

<TargetFrameworks>net6.0;netstandard2.0</TargetFrameworks>

This is causing Dotnet.ProjInfo.Inspect.getProjectInfos to go awry, returning --define:DEBUG in its args. If I change the project file to:

<TargetFramework>net6.0</TargetFramework

I no longer see --define:DEBUG coming through (yet to do a full run though because we have other multi-targeting projects). Interestingly, even if I multi-target one framework it returns --define:DEBUG:

<TargetFrameworks>net6.0</TargetFrameworks>

kentcb avatar Aug 12 '22 06:08 kentcb

Confirmed. If I remove the multi-targeting and build, my #if DEBUG code blocks are not in the bundle. I don't have the time to debug Dotnet.ProjInfo right now, but completely understand if no one else does either, in which case I'll try to get to it sometime in the next couple of weeks.

kentcb avatar Aug 12 '22 07:08 kentcb

Oh my, I would have probably never caught this! Thanks a lot for your investigation @kentcb!

It's very unfortunate the bug is coming from Dotnet.Projinfo. It's been working well but it's been a while since the project is not maintained. I've tried a couple of times to upgrade to Ionide.ProjInfo but I always encountered issues (don't remember exactly now). We could give it a new try or as a last resort, put the code from Dotnet.ProjInfo in Fable's repo and make the necessary fixes (although this increases the maintenance load for Fable).

alfonsogarciacaro avatar Aug 16 '22 04:08 alfonsogarciacaro

I've taken a shot at upgrading to Ionide.ProjInfom that may work, but it's largely untested at the moment. #3097

IanManske avatar Aug 20 '22 20:08 IanManske

This great @IanManske, thanks a lot! I'll take a look 👍 It's possible that we need to retarget the PR to snake_island because we want to release Fable 4 soon as it's getting difficult to keep the branch in sync with main, but I can do that :)

alfonsogarciacaro avatar Aug 22 '22 02:08 alfonsogarciacaro

@alfonsogarciacaro Sounds good! I'll work on retargeting to snake_island.

IanManske avatar Aug 22 '22 16:08 IanManske

Fable 4 has been released and the project cracker layer has been completed re-done.

Can you please check if the problem is fixed fine with the latest Fable 4 version?

MangelMaxime avatar Aug 31 '23 12:08 MangelMaxime