angular: After upgrading to Angular 8, production builds can't load: Failed to load module script: The server responded with a non-JavaScript MIME type of "text/plain". Strict MIME type checking is enforced for module scripts per HTML spec.
đ bug report
Affected Package Angular 8
Is this a regression? YES
Description
My production distribution is being served from Azure Blob Storage static site. Is it possible that serving from the static site is causing this error?
This issue happens in Chrome but not Edge.
After upgrading to Angular 8, production builds canât load. Browser console error: Failed to load module script: The server responded with a non-JavaScript MIME type of âtext/plainâ. Strict MIME type checking is enforced for module scripts per HTML spec.
đŹ Minimal Reproduction
Upgrade an Angular 7 app to Angular 8. Do production build, deploy the production build to Azure Blob storage static web site and attempt to open it.
đ„ Exception or Error
Failed to load module script: The server responded with a non-JavaScript MIME type of "text/plain". Strict MIME type checking is enforced for module scripts per HTML spec.
đ Your Environment
Angular Version:
Angular CLI: 8.0.1
Node: 11.6.0
OS: win32 x64
Angular: 8.0.0
... animations, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Package Version
-----------------------------------------------------------
@angular-devkit/architect 0.800.1
@angular-devkit/build-angular 0.800.1
@angular-devkit/build-optimizer 0.800.1
@angular-devkit/build-webpack 0.800.1
@angular-devkit/core 8.0.1
@angular-devkit/schematics 8.0.1
@angular/cdk 7.3.7
@angular/cli 8.0.1
@angular/material 7.3.7
@ngtools/webpack 8.0.1
@schematics/angular 8.0.1
@schematics/update 0.800.1
rxjs 6.5.2
typescript 3.4.5
webpack 4.30.0
About this issue
- Original URL
- State: closed
- Created 5 years ago
- Reactions: 63
- Comments: 130 (7 by maintainers)
Links to this issue
Commits related to this issue
- Workaround, should be "target": "es2015", but causes build bug: https://github.com/angular/angular/issues/30835 — committed to opinionatedstack/web-angular by patricknee 5 years ago
- docs: add a note about javascript mime-types to the deployment guide Some servers don't serve the .js files with the correnct headers. This change documents the requirement. Fixes #30835 — committed to IgorMinar/angular by IgorMinar 3 years ago
- docs: add a note about javascript mime-types to the deployment guide Some servers don't serve the .js files with the correnct headers. This change documents the requirement. Fixes #30835 — committed to IgorMinar/angular by IgorMinar 3 years ago
- docs: add a note about javascript mime-types to the deployment guide (#42339) Some servers don't serve the .js files with the correnct headers. This change documents the requirement. Fixes #30835 P... — committed to angular/angular by IgorMinar 3 years ago
You must change the property âtargetâ in the file âtsconfig.jsonâ to âes5â. Read this blog entry, âDifferential Loading by Defaultâ:
https://blog.angular.io/version-8-of-angular-smaller-bundles-cli-apis-and-alignment-with-the-ecosystem-af0261112a27
This property chooses between modern or legacy JavaScript based on the browser capabilities:
<script type="module" src="âŠ"> // Modern JS
<script nomodule src="âŠ"> // Legacy JS
Hello, we reviewed this issue and determined that it doesnât fall into the bug report or feature request category. This issue tracker is not suitable for support requests, please repost your issue on StackOverflow using tag
angular-cli
.If you are wondering why we donât resolve support issues via the issue tracker, please check out this explanation.
@Aurora7Sys
I found the source of the problem. Angular 8 removed â type=âtext/javascriptâ from the script tags in index.html. Angular 7 had them which is why it worked with Azure Storage.
We also discovered that the Azure portal manual upload did not add the MIME metadata to .js files that were uploaded. So⊠when I manually uploaded my Angular 8 site, it produced the above errors.
I started using Visual Studio Code to publish my Angular 8 apps to Azure Storage and itâs working because the publish extension adds the correct MIME metadata to the files.
Microsoft will look into correcting the Azure portal manual upload to add the MIME metadata so this canât happen on their server.
@kdawg1406 sounds like a server issue to me. What happens if you serve a production build yourself locally? I bet that works.
@alan-agius4
Why is this closed? This is a regression. ng7 created a proper index.html. At least in some situations, ng8 does not. I have not seen a single âsolutionâ that was not a work-around for an ng8 flaw and unrelated to the consumerâs code. ng8 should not be creating ambiguous script tags.
the easy solution just replace target with es5 in tsconfig,json
"target": "es5",
I got the same problem when I host the files on AWS S3. The problem is from the âtype=âmoduleââ, I had to manually change it into âtype=âtext/javascriptââ to make it work again.
Why âtype=âmoduleââ in Angular 8, Iâm wondering? What is the benefit of it over âtype=âtext/javascriptââ ?
I am not so sure this should be closed or sent off to Stack Overflow just yet. You can reproduce this problem with a brand new version 8.02 âhello worldâ app generated from the CLI. The exact same version 7 app has always worked just fine and still does up on Azure storage. So, since there is not really anything we can do to reconfigure Azure Storege, what can we do to get Version 8 apps running up there? Something has changed that broke this capability and free hosting is a pretty good reason to use Angular. đ
Version 8 apps Do work fine on a ârealâ web server though.
Thanks!
Changing the target to ES5 is not a solution, it is a workaround. It means the typescript compiler canât use modern javascript features and will have to emulate them. I fix it by changing the generated index.html and add the mime type. Not a lot of work but a nuisance.
@lion9 understand. Full disclosure, my solution worked for me because the VS Code Extension that performs the upload to the Azure Blob Storage applied the correct metadata to the .js files.
Angular 8 does publish the .js files differently. If you compare an Angular 7 index.html with the Angular 8 index.html the scripts at the bottom of the file are different. Angular 7 .js files have the type=âtext/javascriptâ where the Angular 8 index.html script files do not add this.
Angular 7
<script type="text/javascript" src="runtime.26209474bfa8dc87a77c.js"></script>
I believe this is the root of the problem, Recommend contacting GitHub and ask them how you can apply the required metadata to the files.
Maybe you can try and add the type=âtext/javascriptâ to the script tags that donât have a type attribute? If I remember correctly half of the files have the attribute, the others donât.
Best regards, Karl
I mean⊠100% true story, I just convinced the guy managing this project to use Angular instead of react, and now I look like an ass-hat because we canât even deploy the application.
This issue is posted on Stack Overflow , but no resolution yet, thanks!
I solved it by creating a task in gulp, I share the steps:
npm install --save-dev gulp
npm install --save-dev gulp-replace
"electron": "ng build --base-href ./ && tsc --p electron && gulp && electron ."
npm run electron
note: In the main electron file, make sure you go to the dist folder of your index.html file Ejemplo:
Check that you are trying to load correct filenames. You are simply getting a 404 from backend and the browser cant load the 404 page as JS as a <script>
2020 and this is still an issue and it is even closed?!?! None of the solutions above worked for me, still not sure what is going on, I have an angular app - ssr on nginx
@Erayus I think it has something to do with getting a modern browser to load the file instead of the other version of the file.
I would reach out to the Angular team, you may be causing a problem.
The server metadata needs to be applied to the files, and they will load correctly.
I do think Angular needs much better docs and testing to explain to developers how to deploy Angular 8 apps.
The original issue was caused by a defect within the Azure portalâs blob storage upload functionality. The portal was not properly setting content types when performing the upload. When using object storage to host static sites it is important that the tools used perform a complete upload of the files including content type. First party tools such as the Azure and AWS CLI provide this functionality. If using custom tools (direct API usage, for example) or third-party tools, please ensure that they are also performing these steps.
Version 8.0 of the Angular CLI introduced the differential loading functionality. This leverages the module script functionality in modern browsers to support loading the appropriate scripts for different browsers. Module scripts provide the ability to use the latest ECMAScript functionality within supported browsers and are needed to use native import functionality.
When using module scripts, the HTML specification mandates that the MIME/content type header for the received data be valid. The content type that should be sent by the server for JavaScript files (
.js
) istext/javascript
(or one of the equivalents found here). Most servers and hosting services will do this automatically as JavaScript files are a common file type. If using object storage services for hosting, commonly used first-party tools for those services will also set the appropriate type when uploading. There is no guarantee that a browser will execute a script (module or otherwise) with an invalid content type. This is especially true when using security-related headers such asX-Content-Type-Options=nosniff
(details). Even if module scripts are not in use, the correct content type header should still be sent by the server.Improper or missing content type headers can have a wide range of negative impacts on a site; some of which are security related. For more information on this please see: https://developer.mozilla.org/en-US/docs/Web/Security/Securing_your_site/Configuring_server_MIME_types
There is also an unrelated error that some may be receiving that presents itself with the same message but a sent content type of
text/html
. This error is generally caused by either missing files on the server, an incompatible deploy URL or base HREF application setting for the deployed location, or a misconfigured server rewrite rule for path-based routing. What is happening in this case is that the path-based routing rewrite rule is being triggered due to a file not being present at the requested location. The rewrite rule in turn causes the index HTML file to be sent which has a content type oftext/html
. If the originally requested file was a script or stylesheet, then the error may be shown since HTML is not a valid script or stylesheet. For information regarding server routing configuration, please see: https://angular.io/guide/deployment#routed-apps-must-fallback-to-indexhtml For information regarding the base HREF, please see: https://angular.io/guide/deployment#the-base-tagAdditional documentation within the deployment guide is in the process of being written to better explain these types of errors as well as steps that can be taken to remedy them.
@thel0ner Agreed this needs to be fixed in the angular CLI. We use S3 for hosting the website as well. The whole benefit of using a SPA is that you donât have to have a full fledged web server to host your application. HTML should just be formatted text that can be read by any browser.
And honestly, itâs going to be things like this that push people to react/vue
Instead of disabling differential loading by forcing an
es5
build, I was able to solve the problem by setting thecrossOrigin
property on the build. The underlying problem was a Chrome bug preventing authentication headers from being sent with the request for the javascript files.Settings
Specify
crossOrigin
for the production build by either modifying the build line item inpackage.json
to be something like"build": "ng build --prod --crossOrigin=anonymous ....
or alternatively set thecrossOrigin
policy in the production configuration of yourangular.json
file. Either method will have the same effect on the build.Explanation:
Per this stackoverflow question, it would appear that when older versions of Chrome (issue occurs in Chrome 70, but has been fixed in some build at or before Chrome 78) see a
<script src="..." type="module">
, Chrome neglects to send authentication headers along with the request for the script file. As such, in many situations, the server is responding with either a 404, or some other authorization exception instead of the requested script resource. The received error page will likely have a MIME type of text, as itâs an error page after all, and not the requested script resource.Setting the
crossorigin
attribute on the<script src="..." crossorigin type="module">
causes these older versions of Chrome to properly send along authentication headers, and thus the correct server resources are returned, instead of the aforementioned 404 / authentication error page.Using the above build parameters forces Angular to add a
crossorigin="anonymous"
attribute to the<script>
tags (notecrossorigin="anonymous"
is the same as a nakedcrossorigin
attribute mentioned in the stackoverflow question).I was facing the same issue but after one hour i found out that i was also playing aroud with apache
.htaccess
for routing the server and there is one rule which isRewriteRule ^ index.html
which is the cause of the error ofnon-JavaScript MIME type of "text/html"
When i have removed that rule and done a hard refresh it is working as it should be, so if you are facing the same issue then also check the
.htaccess
for any intentional or unintentional error and also donât forget to hard refresh after changing it, thanks.That is a webserver related problem. Angular 7 did include a MIME type in the <sripts> tags in index.html:
<script type="text/javascript" src="runtime.26209474bfa8dc87a77c.js">
Angular 8 does not include a MIME type in <script> tags in index.html:
<script src="runtime-es2015.703a23e48ad83c851e49.js"
type=âmoduleâ>`<script src="runtime-es5.465c2333d355155ec5f3.js" nomodule>
Itâs there fore up to the webserver what MIME type is returned when the browser does retrieve the .js file. In my case Internet Explorer and Edge could load the app, Firefox and Chrome did refuse to open the app with error âFailed to load module script: The server responded with a non-JavaScript MIME type of âtext/x-jsâ. Strict MIME type checking is enforced for module scripts per HTML spec.â
The solution was to add a .htaccess file into the root directory of the app on the apache webserver to force the server to deliver .js files as MIME type âtext/javascriptâ. Content of .htaccess:
# Force MIME Type text/javascript for all .js files
# Needed for Angular 8 since type="text/javascript" is not specified anymore in <script> tags in index.html
AddType text/javascript .js
Same issue when packaging with Electron, seems to be resolved by setting type=âtext/javascriptâ instead of type=âmoduleâ.
It is a server issue. This issue was noticed only with Alias apache config.
Under apache 2.4:
Configuration: apache 2.4 Angular CLI version: 8.3
It appears that we can not run an Angular application (from v8) under Alias folder. The workaround is to deploy under a real subfolder.
Let us consider the final url of my_angular_application
https://www.example.com/my_angular_application
The build command is as follows
ng build --prod --baseHref /my_angular_application/
The apache config is as follows
@thel0ner Not everybody uses a full fledged web server. A generated index.html should be parseable by a browser âas isâ, a modification by the web server should not be necessary. I run the the angular generated code from a server based on https://github.com/eidheim/Simple-Web-Server. When you ask it for index.html, it sends you the file unmodified. I really donât understand why the mime type is not added to the script references in the index.html. When I add them manually everything is fine, but it is a nuisance.
https://angular.io/guide/deployment#differential-loading
@ranaivomahaleo And if you are not using a dedicated webwerver such as apache? If you use a very simple server that does no ârewritesâ of the generated index.html, but just serves the file as is? In angular 7 this was no problem, and now I have to edit the index.html manually after each build. I have not seen an explanation in this thread of why this cannot be fixed. I seems trivial to me. (as a developer I am aware that things not always are that simple, but at least give an explanation of why it cannot be fixed)
Adding this to my nginx.conf is the only solution that worked for me
Found the this solution here.
as @Haritsinh mentioned above, I confirm that this is a issue with your server, not ng. perhaps you guys need a better rewrite rules? for example, a extremely poor, simple approach for apache .htaccess would be :
ErrorDocument 404 /index.html
This issue affects anyone using Cordova, as Cordova ultimately serves up files via the
file://
protocol. I canât change my âserverâ to serve up the js files astext/javascript
afaik as there is no server. Thereâs an issue on Cordovaâs github, but I donât know that itâs anything the Cordova team can resolve.Does anyone know if thereâs any support for the
file://
with javascript modules?try browerslist
If you are deploying your build inside the folder in your server, then while generating the prod build make sure you add the folder to the --base-href flag and the folder path. Following is the command if you are deploying inside the âwwwâ folder
ng build --prod --base-href /www/
Finally fixed it in my app after some trial and error. In
angular.json
, I had to change my output path to"outputPath": "dist/",
- See this comment for a deeper diveThis issue appears to happen only if the applicationâs base href is set with flag --base-href to a folder other than â/â. None of the solutions offered here will be to the rescue if that happens.
If possible, serve your application from root (/) of your web server.
$ng build --aot --prod
Omit --base-href=âproject-nameâ
hi here i have a solution that may help to you.
const express = require(âexpressâ); const bodyParser = require(âbody-parserâ); const cors = require(âcorsâ); const path = require(âpathâ);
var app = express(); app.use(bodyParser.json()); app.use(cors());
app.listen(4200, () => console.log(âserver started 4200â));
app.use(express.static(path.join(__dirname,â./dist/<project name>â))); //you can check inside dist folder you must have a folder which is nothing but the projectname; //give the correct path if you create the js file in any other location
app.get(â*â,(req,res)=>{ return res.sendFile(path.join(__dirname,â./dist/<project name>/index.htmlâ)); });
Note : above solution is purely based on nodejs, i attached the angular build file in nodejs path and run it. it is working for me. If you have any doubt let me know
I encountered the same problem For a month or two angular 8 build worked fine for me, but maybe browsers changed something and today the build gave me the same error.
"module": "esnext", "target": "es2015",
downgrading to:
"module": "es2015", "target": "es5",
and changing lazy loading syntax solved this issue, but this is temporary workaround. Is Angular team working on this issue?my angular packages versions:
"@angular/cdk": "8.0.2", "@angular/common": "^8.1.1", "@angular/compiler": "^8.1.1", "@angular/core": "^8.1.1",
You should be defining your output browser support inside the browserslist file. In this case for the lack of support in modern browsers you should be adding something like:
Chrome >= 70 and Chrome <= 75
Adding this inside your browserslist should add support for chrome and chromium based applications.
For additional information you can see this github repo. It has a list of other options for inside the browserslist https://github.com/browserslist/browserslist
I struggled with this issue for a whole day and finally, it was some infra issue with Kubernetes. I donât have details at the moment, but when it happens to you, donât think it is just your angular code issue. This can occur from different layers. Iâll update this post about what went wrong in K8 once I got the post-mortem from our ci team.
@Amitesh as noted elsewhere, if you are running into this on Electron this is expected as the
file://
protocol does not convey mimetypes to the Chromium engine. The recommended solution for Electron is to implement a custom protocol, which is more reliable and does not require any changes/patches to your build output. It also gives you other benefits asfile://
is quite restricted within browser engines.For more information about this, see the Electron docs. You can find folks discussing this solution (and an example custom protocol) at https://github.com/electron/electron/issues/12011#issuecomment-369705509
As described by @clydin in one of the above comments, this is not a bug in Angular itself.
This is mostly a documentation issue.
I am reposting the quoted message below:
It was my first time deploying an Angular App (v9) to Azure and I was having an issue with reloading web pages on a route (F5, Ctrl+F5, Ctrl+R).
I was getting an error âFailed to load module script: The server responded with a non-JavaScript MIME type of âtext/htmlââ.
I was able to solve this by changing my ng build from
ng build --prod --base-href
tong build --prod
.I was able to work around this by manually setting the
type
attribute for each script and css file in theindex.html
in theng build --prod
output folder.e.g.
<script type="application/javascript"></script>
<link rel="stylesheet" type="text/css">
@adamdport This is unfortunately a limitation of Cordova. It does not support module scripts directly. Even something like the following will fail:
To work around this limitation, you can use this plugin: cordova-plugin-ionic-webview. It is used automatically with ionic applications but can also be used by any Cordova application. It also simplifies the use of path-based routing which may also be useful to you.
@philtyl this link should help you on how to set up a mime type in Azure app services https://social.microsoft.com/Forums/Azure/en-US/d3af7fa3-dc2b-415b-b281-333c26f833c5/azure-app-service-mime-type-aac?forum=AzureAPIApps
Also, @Splaktar compiled a compressive list on how to add mime types to various cloud providers: https://github.com/angular/angular/issues/35734#issuecomment-593024055
@btey This worked for me. In earlier version you will find, target=âes2015â. I just removed 2015 and added 5. target=âes5â
We also solved the issue server-side. In our case, we tweaked a setting in Akamai that will always set the correct mime type for JS files.
defer and nomodule attributes are not identifiable for the thymeleaf resolver and those are not well formatted on the index.html script tags because of that the angular 8 version is not such helpful for the user who use thymeleaf , please give us a solution for that issue , other version upto angular 7 are working well but this version is not work as expected , thanks
i solved this in tsconfig.json change target to es5 and module to commonjs
Ex: { âcompileOnSaveâ: false, âcompilerOptionsâ: { âbaseUrlâ: â./â, âoutDirâ: â./dist/out-tscâ, âsourceMapâ: true, âdeclarationâ: false, âdownlevelIterationâ: true, âexperimentalDecoratorsâ: true, âmoduleâ: âcommonjsâ, âmoduleResolutionâ: ânodeâ, âimportHelpersâ: true, âtargetâ: âes5â, âtypeRootsâ: [ ânode_modules/@typesâ ], âlibâ: [ âes2018â, âdomâ ] }, âangularCompilerOptionsâ: { âfullTemplateTypeCheckâ: true, âstrictInjectionParametersâ: true } }
While this only treats the symptom, you can opt out of differential loading to buy you some time to deal with the problem.
We use ADO build pipelines to drop files into blob storage running static website and fronted with a CDN, so I may be looking at just running a custom post-copy PS script again like in the earlier days to apply correct mime types.
@spock123 thank you for your remarks. Iâll try this in the morning.