I'm making a Chrome extension and I'm trying to import a Typescript file in Javascript.
Both files are next to each others.
I'm importing it this way:
import { ApiParsing } from './ApiParsing.ts';
When I'm using the extension I have the following error:
Failed to load module script: The server responded with a non-JavaScript MIME type of "". Strict MIME type checking is enforced for module scripts per HTML spec.
TypeScript cannot be executed from a browser / node.js environment directly. At first you have to transpile it into native javascript. To do this you will need to execute tsc.
https://www.typescriptlang.org/docs/handbook/compiler-options.html
https://www.typescriptlang.org/docs/tutorial.html
Typescript is a so called "Superset" of JavaScript which means that all typescript code will be transpiled into usual JS code from the typescript compiler. Often those compile processes are linked with a bundler like webpack.
https://webpack.js.org/concepts/
Knowing this your error The server responded with a non-JavaScript MIME type makes a lot of sense due to a typescript file is a "non-JavaScript MIME type".
Note:
You can't import typescript files into javascript files, but you can do it vice versa.
You can do that through babel. Follow below article
Article: How to use typescript file in javascript project
Related
I'm trying to get a handle on Node and ES modules. Specifically how/if you can omit the file extension from the path string value of the import statement (and optionally get VSCode to autocomplete those paths).
I understand you can either gives files the .mjs extension or set "type" = "modules" in the package.json but both approaches lead to the following problems.
VSCode won't autocomplete the path if the file extension is .mjs, it only sees the file if it's .js. However if it is .js the autocomplete omits the extension from the string and the import fails until I add it manually.
Trying to use a library like graphql inside my own modules also fails because all the import statements between the .mjs files in the graphql module have been written omitting the extension from the string.
SO... when is not including the extension valid with ES6 module imports, and is there anyway to get this condition enabled with NodeJS?
The node.js ES6 module implementation specifically does not do automatic file extension resolution as documented in https://nodejs.org/api/esm.html#esm_customizing_esm_specifier_resolution_algorithm :
The current specifier resolution does not support all default behavior of the CommonJS loader. One of the behavior differences is automatic resolution of file extensions and the ability to import directories that have an index file.
However this can be changed by a command line argument --experimental-specifier-resolution=[mode]
As such not giving a file extension is invalid by default but can be made valid depending on how you run node.js.
However, there are systems implemented before the ES6 spec was written that implements ES6-like import syntax such as Typescript and Babel. These systems assumed you can exclude file extensions in your imports. If you are using such a system to compile your ES6 imports to ES5 syntax you can exclude file extensions, sometimes, depending on if the version of the compiler you are using supports it.
I have a working Flask app that I'm trying to refactor to use ES6 imports. I don't need it to run on old browsers, and ES6 imports work in modern browsers without transpilation, right?
I'm just running this via Flask's built-in server at the moment. The production app is served via gevent instead, but I'm obviously not at that point with these changes yet.
Below is what I've tried so far. Where have I gone wrong?
views.py
#app.route('/home')
def serve_home():
return render_template('home.html')
formatting.js
export function formatNumber(...) {
...
}
Attempt 1
home.html
<script type="text/javascript" src="/static/js/main.js"></script>
main.js
import {formatNumber} from "/static/js/formatting.js";
Error (main.js, line 1)
Uncaught SyntaxError: Unexpected token {
Attempt 2
Changed the script type to "module"
home.html
<script type="module" src="/static/js/main.js"></script>
Error (main.js, line 1)
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.
Attempt 3
Changed the extension of each of the two Javascript files from "js" to "mjs"
home.html
<script type="module" src="/static/js/main.mjs"></script>
main.mjs
import {formatNumber} from "/static/js/formatting.mjs";
Error (main.mjs, line 1)
Failed to load module script: The server responded with a non-JavaScript MIME type of "application/octet-stream". Strict MIME type checking is enforced for module scripts per HTML spec.
For those of you getting the error:
The server responded with a non-JavaScript MIME type [...]
...you'll want to confirm python is returning the expected mimetype of your JS files.
>>> import mimetypes
>>> mimetypes.guess_type("notExists.js")
('text/javascript', None)
For myself, using a Windows platform to host the web server from (eg. Flask's development server), I found I needed to update the registry to associate the file extension with text/javascript.
For example, in the registry editor:
Under HKEY_CLASSES_ROOT, find .js (and .mjs if using that)
Look at the value for "Content Type". It must say text/javascript, NOT text/plain, or application/octet-stream, etc.
this worked for me:
import mimetypes
mimetypes.add_type('application/javascript', '.mjs')
added this code before launching flask
I'm pretty sure you will need to use webpack and babel to transpile your code.
There is a webpack plugin for Flask that might be of use https://pypi.org/project/Flask-Webpack/ https://github.com/nickjj/flask-webpack
You could also follow this https://itnext.io/a-template-for-creating-a-full-stack-web-application-with-flask-npm-webpack-and-reactjs-be2294b111bd or https://codeburst.io/creating-a-full-stack-web-application-with-python-npm-webpack-and-react-8925800503d9 tutorials. Just ignore the parts about react
This post ES6 build chain python backend (flask) not SPA seems to be a similar one to yours as well.
I don't need it to run on old browsers, and ES6 imports work in modern browsers without transpilation, right?
It depends on browser spectrum of your intended application users.
There is documented support for ES6 imports in modern web browsers.
See the list of supported browsers to be sure that you're viewing your application in a supported browser version.
The script extension ought to be .js and not .mjs as documented in the above link.
I noticed that the error reported is one that as to do with mimetype. Flask is returning an application/octet-stream for the mimetype of the static file where it is unable to guess the mimetype.
You can correct this using the url_for template function to build the url for the file pointing at a view that returns an appropriate mimetype.
<script type="module" src="{{ url_for('es6-static', filename='/js/main.js') }}"></script>
#app.route('/es6-static/<path:filename>')
def es6_static(filename):
return send_from_directory(app.config['ES6_MODULES'],
filename, as_attachment=True,
mimetype='text/javascript'
)
While text/javascript is a deprecated mime/type for JS resources, you may have better support for it in browsers.
I strongly suggest to use gunicorn or nginx to serve the static files as the above is only goes as far as helping with development.
I am trying to make a Rust WebAssembly project and have modified the rust-webpack-template as my starting point. The template is a webpack project with a JavaScript file that calls a single Wasm function and the Rust Wasm takes over from there.
I have modified the template because I would like to have my main logic in JavaScript and call the Rust Wasm through an API.
I have changed the webpack entry to bootstrap.js shown below.
// bootstrap.js
import("./index.js").catch(e =>
console.error("Error importing 'index.js':", e)
);
I added the file index.js and it calls the Rust Wasm functions
// index.js
import * as wasm from "../crate/pkg/rust_webpack";
const title = document.getElementById("msg");
title.innerText = wasm.get_msg();
The get_msg function from Rust looks like this:
#[wasm_bindgen]
pub fn get_msg() -> String {
"Hello from Rust WebAssembly!".to_owned()
}
When I run the project using webpack-dev-server -d, everything works fine.
However, when I build the project using webpack and try and host the generated files directly, nothing is displayed and the browser console displays the error:
Error importing 'index.js': TypeError: "Response has unsupported MIME type"
This error comes from the code in bootstrap.js but I'm not entirely sure what it means or how to fix this error.
Why do things work when serving with the webpack dev server but not after bundling everything together?
As Shepmaster helped me to figure out in the comments, the MIME type of the .wasm file is being set to application/octet-stream when the browser expects it to be application/wasm.
I am using a simple express server to host my files. Express can be configured to use the correct MIME type with a single line.
var express = require('express');
var app = express();
// Set the MIME type explicitly
express.static.mime.define({'application/wasm': ['wasm']});
app.use(express.static('./dist'));
app.listen(3000);
According to this issue, express will handle .wasm files correctly after version 4.17. It works correctly in webpack dev server because they implemented their own workaround while they wait for the fix in express.
I had a similar problem ("Response has unsupported MIME type") with Flask. The problem was that I didn't have a separate route to the .wasm file. For example:
#app.route('/path/to/file.wasm')
def wasm_file():
return send_file('/path/to/file.wasm', mimetype = 'application/wasm');
It is not the answer to this question, but it's a hint for other people who have a similar problem.
I also encountered this problem, leading me to change my .htaccess file (I'm using Apache to host my local server) to include the following:
AddType application/wasm wasm
If the error persists, and you are getting this error from using WebAssembly.instantiateStreaming, this related question may have an explanation and workaround: WebAssembly InstantiateStreaming Wrong MIME type
I have a JS file that imports a module:
import { LitElement, html } from '../lib/#polymer/lit-element/lit-element.js';
This causes a load of TypeScript errors, some due to versions, some due to a test framework used by some of the modules, some due to different noImplicitAny or strictNullChecks settings, but most due to Yarn flattening the npm hierarchy (and not rewriting internal references).
None of these are errors in my code, and I'm not even referencing the TS directly - most are coming from the TS source for that JS file.
How do I stop these from breaking my build? I don't care whether the source or test TS files compile in place, I only need the result JS file.
Even in TS files I don't want TSC to recompile the referenced Yarn modules - at most it should use them for type checking (and even then prefer a *.d.ts file over the source).
I've tried --noResolve and that doesn't fix it (and also breaks the es2017 lib references).
I was going through Angular2 quickstart tutorial with Javascript and Typescript as well, In javascript version I observed that components and modules are first assigned to a variable (window.app which I understood as some global variable that can be accessed across js files or script blocks) and that is fine. Coming to type script version just export and import were used, I tried to analyze the generated javascript code but understood nothing. Can some one explain me how this export and import works in Tyepescript.
Import and export in typescript are explained well by the documentation here https://www.typescriptlang.org/docs/handbook/modules.html.
Like toskv said in his comment, how those statements in your TypeScript files get transpiled into statements in your JavaScript files depends largely on the module system you set up in your tsconfig.json file.
For example, setting "module": "commonjs" will cause the TypeScript compiler (tsc) to transform your import/export statements into essentially node.js-style require() statements. This documentation has a few simple, but helpful, examples of how node.js modules work: https://nodejs.org/api/modules.html.
Using a setting of "systemjs" instead of "commonjs" will make TypeScript translate your import/export statements into a format that SystemJS understands, of which I am no expert.
This process is further complicated by the fact that Angular 2 projects also require build steps that take the transpiled JavaScript files and turn them into packaged "bundles." These bundled files are (depending on your configuration settings) concatenated, minified, and perhaps even uglified. So looking at the final javascript code that is run is really not helpful, as it was not written by humans.
For example, the Webpack build system (google webpack.js) takes require() statements it finds in JavaScript code and does some magic to wrap each module in its own __webpack_require__ function, which allows the build system to take your whole project file structure and bundle it in to one or several JavaScript files which still maintain their dependencies on each other.
In other words, by the time you look at the production JavaScript code, it's not meant to be intelligible by human readers. The flow can be simply represented by TS Source Code > TS Transpilation into JS Code > Module/Dependency Build Steps into Production JS Code.
TL;DR TypeScript doesn't actually handle the module importing/exporting. During transpilation, it converts those statements into statements other module systems (node.js or SystemJS) can understand, which are in turn converted into production code for serving an Angular 2 application.