I have a module in TypeScript that look as follows:
import { CallerId, CallScreening, CustomTagRef, MediaRef, OutboundSettings, ServiceCommon }
from '../src/shared/domain/dto';
import { ServiceCommonEntity } from '../src/shared/domain/entity';
import { CallerIdMode, ResourceRefType } from '../src/shared/domain/enum';
export const CONTACT_PAYLOAD = 'payload';
export const ACCOUNT_PAYLOAD = 'a_payload';
export function getFakeAccountPayload() {
return fake_payload;
}
In the same project I have a js file in which I want to use functions from my .ts file.
How can I import my ts module to my js file?
Sometimes we face such situation in our projects. I am pretty sure that you are migrating some part of your code to typescript and somewhere in your project you need typescript in javascript file and creating javascript file for same ts file is not way to solve the problem, but If you really want to use typescript(.ts) in javascript(.js) files, so here is the one possible solution, I am assuming that your are suing webpack bundler, so you use ts-loader and babel-loader in your webpack. here are rule for your webpack configuration(Note: you must have airbnb preset, ts-loader, and all plugins installed)
{
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{
test: /\.jsx?/,
use: {
loader: 'babel-loader',
options: {
presets: ['airbnb'],
plugins: ['#babel/plugin-transform-modules-commonjs', '#babel/transform-async-to-generator', 'source-map-support', 'babel-plugin-root-import'],
ignore: ['node_modules/is_js'],
},
},
exclude: /node_modules\/(?query-string|strict-uri-encode)/,
}
]
}
In case of running spec, if you are using jest you might also need .babelrc configuration for tests
{
"presets": [
"airbnb",
"#babel/preset-typescript"
],
"env": {
"development": {
"sourceMaps": true,
"plugins": ["source-map-support"]
}
},
"plugins": ["#babel/plugin-transform-modules-commonjs", "#babel/plugin-proposal-class-properties", "#babel/transform-async-to-generator", "babel-plugin-root-import"],
"ignore": ["node_modules/is_js"]
}
We also have one article which might be helpful. Use .ts File .js file
Related
I'm working on a component library that wraps some of the MaterialUI components and implements others to be used in a larger project. While setting up the library I had to setup webpack in order to be able to import and bundle images and css files in my library.
This library is located nested in the folder of the main project, where I add it as a dependency with npm i ./shared/path_to_library. this seems to work fine, since the typescript is working correctly and the npm start gives me no error. Then when I open it in a browser I get the following error page:
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:
1. You might have mismatching versions of React and the renderer (such as React DOM)
2. You might be breaking the Rules of Hooks
3. You might have more than one copy of React in the same app
But this error only occurs if I try to use any component from #mui/material inside my library. Exporting handmade components and using them in the main project works fine, but using any material component wrapped by my own component and then using it in the project brings me to this error. I also tried to move from webpack to rollup but I ended up getting the same problem.
Here are my config files for webpack and rollup:
rollup.config.js
import resolve from "#rollup/plugin-node-resolve";
import commonjs from "#rollup/plugin-commonjs";
import typescript from "#rollup/plugin-typescript";
import dts from "rollup-plugin-dts";
const pkg = require("./package.json");
const config = [
{
input: "src/index.ts",
output: [
{ file: pkg.main, format: "cjs", sourcemap: true },
{ file: pkg.module, format: "esm", sourcemap: true },
],
plugins: [
resolve(),
commonjs(),
typescript({ tsconfig: "./tsconfig.json" }),
],
},
{
input: "lib/esm/types/index.d.ts",
output: [{ file: "lib/index.d.ts", format: "esm" }],
plugins: [dts()],
},
];
export default config;
webpack.config.js
const path = require("path");
module.exports = {
entry: "./src/index.ts",
mode: "development",
output: {
path: path.resolve(__dirname, "lib"),
filename: "[name].js",
libraryTarget: "umd",
library: "my-core-library",
umdNamedDefine: true,
},
devtool: "source-map",
module: {
rules: [
{
test: /\.css?$/,
use: ["style-loader", "css-loader"],
exclude: /node_modules/,
},
{
test: /\.tsx?$/,
use: ["babel-loader", "ts-loader"],
exclude: /node_modules/,
},
{
test: /\.(png|jpe?g|gif|svg)$/,
use: ["file-loader"],
exclude: /node_modules/,
},
],
},
resolve: {
extensions: [".ts", ".tsx", ".js", ".jsx"],
},
externals: [
{
react: "react",
"react-dom": "react-dom",
"#mui/material": "#mui/material",
"#emotion/react": "#emotion/react",
"#emotion/styled": "#emotion/styled",
"#mui/lab": "#mui/lab",
},
],
};
I'm running out of ideas :(
This is probably happening because multiple instances of React are loaded. You can check with npm ls react, all react packages should be deduped
A short term solution is to link the react from the library, ie
npm link ../shared/path_to_library/node_modules/react
However you would have to re-link that everytime you install an npm package.
I think you need to configure your .babelrc as following:
"presets": ["#babel/preset-env", "#babel/preset-react", "#babel/preset-typescript", "jest"],
"plugins": [
[
"babel-plugin-transform-imports",
{
"#material-ui/core": {
"transform": "#material-ui/core/${member}",
"preventFullImport": true
},
"#material-ui/icons": {
"transform": "#material-ui/icons/${member}",
"preventFullImport": true
}
}
]
]
I am creating a basic structure where the controller.js would need some Views to be imported from view.js and hence this is what I am using in the controller.js
import View from './View'
However there was an issue with the bundler with webpack and I ended up visiting this page
https://webpack.js.org/loaders/imports-loader/
and below is webpack.config.js.. I've added the lines at the end to the RULES as metioned in the documentation
I ran npm install npm install imports-loader --save-dev
// SOURCE OF TUTORIAL
// https://www.youtube.com/watch?v=MpGLUVbqoYQ&t=1205s
const HtmlWebpackPlugin = require("html-webpack-plugin");
const path = require("path");
module.exports = {
mode: "development",
devtool: false,
entry: {
main: "./src/js/controller.js",
model: "./src/js/model.js",
},
plugins: [
new HtmlWebpackPlugin({
template: "./src/main.html",
}),
],
module: {
rules: [
{
test: /\.scss$/,
use: [
"style-loader", // injects STYLES into DOM
"css-loader", // turns CSS into commonjs
"sass-loader", // turns SASS into CSS
],
},
{
test: /\.html$/,
use: ["html-loader"],
},
{
test: /\.(png|gif|svg|jpe?g)$/,
type: "asset/resource",
},
{
test: require.resolve("./path/to/example.js"),
loader: "imports-loader",
options: {
type: "module",
imports: "default lib myName",
},
},
],
},
};
The last section of the rule is what I have added.. it's a basic copy paste without really understanding what it does and it didn't work.. I am obviously doing somethibg wrong but I could not figure it out even after reading the section at the link above..
Could someone explain how the last section should be configured so that I am able to use import? I've recently created this webpack configuration based on a youtube tutorial so my knowledge on webpack is very basic..
Any help would be appreciated.
I have a Vue.js Single File Component which depends on primevue/AutoComplete.vue.
When transpiling the code for IE11 (I know, I know) the files produced from AutoComplete.vue are ignored and therefor not transpiled resulting in errors in Internet Explorer.
I have adjusted my babel-loader config as described here and the relevant part of my webpack config now looks like this:
{
test: /\.vue$/,
loader: 'vue-loader'
},
{
test: /\.js$/,
use: [
{
loader: 'babel-loader',
options: {
exclude: file => (/node_modules/.test(file) && !/\.vue\.js/.test(file))
},
presets: [
["#babel/preset-env",
{
"useBuiltIns": "usage",
"debug": true,
"modules": false,
"corejs": { version: "3.6", proposals: true }
}
]
]
}
}
]
},
Looking at the suggested exclude function, it relies on files having the suffix e.g. AutoComplete.vue.js but when I log the "file" parameter, I don't see any file with this suffix.
How is it supposed to filter the nested Vue dependencies if the proposed file ending isn't provided by vue-loader ? Am I missing these dependencies because of a config error ?
I'm trying to use the TypeScript benefits in a Vue SFC,
Install the ts-loader, typescript dependencies
I added the tsconfig.json configuration
// tsconfig.json
{
"compilerOptions": {
// this aligns with Vue's browser support
"target": "es5",
// this enables stricter inference for data properties on `this`
"strict": true,
// if using webpack 2+ or rollup, to leverage tree shaking:
"module": "es2015",
"moduleResolution": "node"
}
}
But when trying to compile the next component it shows me error.
<script lang="ts">
import Vue from "vue";
import { mapState,mapGetters } from 'vuex'
export default Vue.extend({
data() {
return {
number : 0
}
},
methods:{
// error void
upCount() : void {
this.$store.commit('increment');
},
downCount() : void{
this.$store.commit('decrement');
},
upCountBy() : void {
this.$store.commit('incrementBy',{count : this.number});
}
},
....
the error
Module parse failed: Unexpected token (45:12) You may need an
appropriate loader to handle this file type.
I am using VueJs together with WebPack from a Laravel and Laravel Mix base installation. How do I solve this?
When I started using Vue and TypeScript, I ran into similiar problems at first and it took me quite a while to get it to work. Try adding this to your webpack.config.js
...
module: {
rules: [
{
test: /\.tsx?$/,
use: [{
loader: 'ts-loader',
options: {
appendTsSuffixTo: [ /\.vue$/ ]
}
}],
exclude: /node_modules/
},
// make sure vue-loader comes after ts-loader
{
test: /\.vue$/,
loader: 'vue-loader'
},
...
Try and flip the order of Connum's suggested answer.
module: {
rules: [
{
test: /\.vue$/,
use: 'vue-loader',
},
{
test: /\.ts$/,
exclude: /node_modules/,
use: [{ loader: 'ts-loader', options: { appendTsSuffixTo: [/\.vue$/] } }],
},
]
}
Worked for me. You have installed the vue-loader?
npm i -D ts-loader typescript vue-loader
Babel's 6th version changes the functioning of export default and in particular its relation with commonjs require.
To summarise, while until babel5, require('module') where giving the default export of the module, it now always returns the module object containing all of the exports of the module.
If one only wants the default, he/she must use require('module').default.
As explained here, there is very good reasons behind this and the aim of this question is not to break or hack this behaviour.
However, if one is building a library, he/she usually does not want to distribute a module but the export value of his library (e.g. a function, whatever module system is used internally).
This is well dealt with by webpack and the output.library configuration when using commonjs or AMD. Because prior babel's versions allowed the default export to be required with commonjs, babel was also compatible with this mechanism. However it is not the case anymore: the library now always provides an es6 module object.
Here is an example.
src/main.js
export default "my lib content";
webpack.config.js
var path = require("path");
var webpack = require("webpack");
module.exports = {
entry: {
lib: [ path.resolve(__dirname, "src/main.js") ],
},
output: {
path: path.join(__dirname, "dist"),
filename: "mylib-build.js",
library: 'myLib'
},
module: {
loaders: [
{
test: /\.js$/,
loader: "babel",
include: path.join(__dirname, "src"),
query: { presets: ['es2015'] }
}
]
}
};
test.html
<html>
<head></head>
<body>
<script src="dist/mylib-build.js"></script>
<!-- `myLib` will be attached to `window` -->
<script>
console.log(JSON.stringify(myLib)); // { default: "my lib content" }
</script>
</body>
</html>
This is a very simple example but I obviously want the export of mylib to be the string "my lib content" instead of { default: "my lib content" }.
One solution could be to create an export source file in commonjs to perform the transformation:
module.exports = require('./main').default;
However I find this solution quite poor. One should be able to solve it at the compilation level, without changing the source code.
Any idea?
Was just going at this my self. Whether one like to call it a workaround or solution, there seem to be a Babel plugin that "solve it".
Using the plugin babel-plugin-add-module-exports as referenced in https://stackoverflow.com/a/34778391/1592572
Example config
var webpackOptions = {
entry: {
Lib1: './src/Lib1.js',
Lib2: './src/Lib2.js'
},
output: {
filename: "Master.[name].js",
library: ["Master","[name]"],
libraryTarget: "var"
},
module: {
loaders: [
{
loader: 'babel',
query: {
presets: ['es2015'],
plugins: ["add-module-exports"]
}
}
]
}
};
This yields Master.Lib1 to be lib1 instead of Master.Lib1.default.
Webpack 2 now supports es6 modules which partially solves this issue. Migrating from webpack 1 to webpack 2 is relatively painless. One just needs to remember to disable babel's es6 module to commonjs conversion to make this work:
.babelrc
{
"presets": [
["es2015", {"modules": false}]
]
}
However, unfortunately, it does not work properly with export default (but an issue is opened, hopefully a solution will be released eventually).
EDIT
Good news! Webpack 3 supports the output.libraryExport option that can be used to directly expose the default export:
var path = require("path");
var webpack = require("webpack");
module.exports = {
entry: {
lib: [ path.resolve(__dirname, "src/main.js") ],
},
output: {
path: path.resolve(__dirname, "dist"),
filename: "mylib-build.js",
library: "myLib",
// Expose the default export.
libraryExport: "default"
},
module: {
loaders: [
{
test: /\.js$/,
loader: "babel",
include: path.resolve(__dirname, "src")
}
]
}
};
You can use this solution (this is more like workaround, but it allow you to keep your sources from change):
There is a loader called callback-loader. It allow you to change your sources in a build time by calling a callback and put a result instead of it. In other words you can turn all you require('module') into a require('module').default automatically in a build time.
Here is your config for it:
var webpackConfig = {
module: {
loaders: [
{ test: /\.js$/, exclude: /node_modules/, loader: 'callback' },
...
]
},
...
callbackLoader: {
require: function() {
return 'require("' + Array.prototype.join.call(arguments, ',') + '").default';
}
}
};