currently i am using bable-loader to generate the javascript from typescript. but i want to generate typescript declarations as well.
to solve this originally i simply added tsc --emitDeclarationOnly at the end of our build script.
this approach works for building but not for watch
hence i wanted to still use the ts-loader just of emitDeclarationsOnly. how ever i kept getting the following error
lerna ERR! yarn run build stdout:
$ cross-env NODE_ENV=production webpack --config ./webpack.config.js --mode production
assets by status 122 KiB [cached] 117 assets
./src/index.ts 39 bytes [built]
ERROR in ./src/index.ts
Module build failed (from ./node_modules/ts-loader/index.js):
Error: TypeScript emitted no output for G:\SOMEPATH\src\index.ts.
at makeSourceMapAndFinish (G:\SOMEPATH\node_modules\ts-loader\dist\index.js:53:18)
at successLoader (G:\SOMEPATH\node_modules\ts-loader\dist\index.js:40:5)
at Object.loader (G:\SOMEPATH\node_modules\ts-loader\dist\index.js:23:5)
webpack 5.11.1 compiled with 1 error in 8620 ms
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.
my tsconfig is
{
"compilerOptions": {
"alwaysStrict": true, /* Parse in strict mode and emit "use strict" for each source file. */
"declaration": true,
"declarationMap": true,
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
"emitDeclarationOnly": true,
"lib": ["ESNext", "DOM"],
"module": "esnext",
"moduleResolution": "node", /* Specify module resolution strategy: 'node' (Node.js) or 'classic' (TypeScript pre-1.6). */
"noImplicitAny": true,
"noImplicitReturns": true,
"noImplicitThis": true, /* Raise error on 'this' expressions with an implied 'any' type. */
"useDefineForClassFields": true,
"outDir": "./dist/",
"sourceMap": true,
"strict": true, /* Enable all strict type-checking options. */
"strictFunctionTypes": true, /* Enable strict checking of function types. */
"strictNullChecks": true, /* Enable strict null checks. */
"strictPropertyInitialization": true, /* Enable strict checking of property initialization in classes. */
"target": "es2015",
"types": []
/* Module Resolution Options */
},
"exclude": ["node_modules"],
"files": [
"./src/index.ts",
"./src/index.d.ts",
]
}
webpack
/* eslint-disable #typescript-eslint/no-var-requires */
const path = require('path');
const isProduction = process.env.NODE_ENV === 'production';
module.exports = {
cache: {
type: 'filesystem',
},
devtool: isProduction ? 'source-map' : 'source-map',
entry: './src/index.ts',
module: {
rules: [
{
enforce: 'pre',
exclude: /node_modules/,
test: /\.(ts|tsx)$/,
use: [
{
loader: require.resolve('eslint-loader'),
options: {
eslintPath: require.resolve('eslint'),
},
},
],
},
{
exclude: /node_modules/,
use: ['ts-loader'],
},
{
exclude: /node_modules/,
test: /\.tsx?$/,
use: ['babel-loader'],
},
],
},
output: {
filename: 'index.js',
globalObject: 'this',
library: 'data',
libraryTarget: 'umd',
path: path.resolve(__dirname, 'dist'),
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
},
};
You can use this plugin to suppress the error message.
/**
* ts-loader emits an error when no output is generated. This occurs when using Typescript's emitDeclarationOnluy
* flag. This plugin suppresses that error so that webpack will consider it a clean build.
*/
class EmitDeclarationOnly {
apply(compiler) {
compiler.hooks.shouldEmit.tap('EmitDeclarationOnly', (compilation) => this.handleHook(compiler, compilation));
}
handleHook(compiler, compilation){
compilation.errors = compilation.errors.filter((error) => {!error.toString().includes("TypeScript emitted no output for")});
}
}
Usage:
yourWebpackConfig.plugins = [new EmitDeclarationOnly()];
Related
What I need to do:
Create a shared runtime environment so that my excel custom functions can have access to the workbook information.
Current Setup:
The way the project seems to have been set up is, using the yeoman office generator to generate a custom function addin and then using vue-cli to generate a vue app to use as the taskpane.
Folder Structure:
RootFolder
Add-In
dist
node_modules
src
config.json
manifest.xml
jest.config.js
package.json
tsconfig.json
webpack.config.js
Taskpane
dist
public
node_modules
src
assets
modules
plugins
router
store
views
App.vue
main.ts
shims-vue.d.ts
shims.tsx.d.ts
shims.vuetify.d.ts
.browserlistrc
.eslintrc.js
babel.config.js
package.json
tsconfig.json
vue.config.js
Webpack config for addin prior to changes:
module.exports = async (env, options) => {
const dev = options.mode === "development";
const buildType = dev ? "dev" : "prod";
const config = {
node: {
fs: 'empty' // https://github.com/webpack-contrib/css-loader/issues/447
},
devtool: "source-map",
entry: {
functions: "./src/functions/functions.ts",
polyfill: "#babel/polyfill",
commands: "./src/commands/commands.ts"
},
resolve: {
extensions: [".ts", ".tsx", ".html", ".js"]
},
module: {
rules: [
{
test: /\.ts$/,
exclude: /node_modules/,
use: "babel-loader"
},
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: "ts-loader"
},
{
test: /\.html$/,
exclude: /node_modules/,
use: "html-loader"
},
{
test: /\.(png|jpg|jpeg|gif)$/,
loader: "file-loader",
options: {
name: '[path][name].[ext]',
}
}
]
},
plugins: [
new CleanWebpackPlugin({
cleanOnceBeforeBuildPatterns: dev ? [] : ["**/*"]
}),
new CustomFunctionsMetadataPlugin({
output: "functions.json",
input: "./src/functions/functions.ts"
}),
new EnvironmentPlugin({
NODE_ENV: env.NODE_ENV || 'local'
}),
new HtmlWebpackPlugin({
filename: "functions.html",
template: "./src/functions/functions.html",
chunks: ["polyfill", "functions"]
}),
new CopyWebpackPlugin([
{
to: "[name]." + buildType + ".[ext]",
from: "manifest*.xml",
transform(content) {
if (dev) {
return content;
} else {
return content.toString().replace(new RegExp(urlDev, "g"), urlProd);
}
}
}
]),
new HtmlWebpackPlugin({
filename: "commands.html",
template: "./src/commands/commands.html",
chunks: ["polyfill", "commands"]
})
],
devServer: {
headers: {
"Access-Control-Allow-Origin": "*"
},
https: (options.https !== undefined) ? options.https : await devCerts.getHttpsServerOptions(),
port: process.env.npm_package_config_dev_server_port || 4000
}
};
return config;
};
Main.ts File:
import Vue from "vue";
import App from "./App.vue";
import router from "./router";
import store from "./store/index";
import vuetify from "./plugins/vuetify";
Vue.config.productionTip = false;
/* eslint-disable-next-line #typescript-eslint/no-explicit-any */
(window as any).Office.onReady(() => {
new Vue({
router,
store,
vuetify,
render: (h) => h(App),
}).$mount("#app");
});
tsconfig.json - add-in
{
"compilerOptions": {
"allowJs": true,
"baseUrl": ".",
"esModuleInterop": true,
"experimentalDecorators": true,
"jsx": "react",
"module": "commonjs",
"noEmitOnError": true,
"outDir": "lib",
"resolveJsonModule": true,
"sourceMap": true,
"target": "es5",
"lib": [
"es2015",
"dom"
]
},
"exclude": [
"node_modules",
"dist",
"lib",
"lib-amd"
]
}
tsconfig.json - taskpane
{
"compilerOptions": {
"target": "esnext",
"module": "esnext",
"strict": true,
"jsx": "preserve",
"importHelpers": true,
"moduleResolution": "node",
"experimentalDecorators": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true,
"baseUrl": ".",
"types": [
"webpack-env",
"node"
],
"paths": {
"#/*": [
"src/*"
]
},
"lib": [
"esnext",
"dom",
"dom.iterable",
"scripthost"
]
},
"include": [
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.vue",
"tests/**/*.ts",
"tests/**/*.tsx"
],
"exclude": [
"node_modules"
]
}
The Add-In folder holds the custom functions and the Taskpane folder holds the Vuejs app. I have left out other default files and added these because I believe they will help communicate my possible issue.
Steps To Merge:
I have edited Manifest.xml following the steps provided on Microsofts documentation.
Updated name to use SharedRuntime
<Set Name="SharedRuntime" MinVersion="1.1"/>
Added Runtimes tags within the Host tag
<Runtimes>
<Runtime resid="Taskpane.Url" lifetime="long" />
</Runtimes>
Updated the Page tag to use Taskpane.Url
<Page>
<SourceLocation resid="Taskpane.Url"/>
</Page>
Updated the FunctionFile tag with Taskpane.Url
<FunctionFile resid="Taskpane.Url"/>
In webpack.config.js:
I have removed the HtmlWebpackPlugin references and replaced with the following.
new HtmlWebpackPlugin({
filename: "index.html",
template: "../taskpane/public/index.html",
chunks: ["polyfill", "taskpane", "commands", "functions"]
})
Steps I did not provided in the Documentation:
Since the project was created using the yeoman office generator with the customfunctions option selected, I believe I needed to add the following to the webpack.config.js file's entry object:
entry: {
functions: "./src/functions/functions.ts",
polyfill: "#babel/polyfill",
commands: "./src/commands/commands.ts",
taskpane: "../taskpane/src/main.ts" <----- new addition
Problem:
When I try to build the project it throws errors such as:
ERROR in ../taskpane/src/main.ts
Module build failed
Error: TypeScript emitted no output for main.ts
Module not found errors
Property doesn't exist errors
More Info:
I'm thinking (but would love to confirm) that the steps I took to create the shared runtime provided by the documentation are indeed correct, along with adding the taskpane file to the entry object in the webpack config. But I just can't figure out why it won't compile. I'm thinking it has to do with the different tsconfig.json configurations. The addin is using target: "es5" while taskpane is using target: "esnext". There are other differences as well. If somebody can help me with this and needs that information, I will be more than happy to add it.
I have a React Library that I want to make buildable using Webpack. The library is written using Typescript. It seems everything is working, but for some reason enums aren't.
When I install the library into my React App, I find Cannot read properties of undefined in the browser console for the enum.
I've tried looking in the outputted bundle and it does appear that the enum is being compiled into the bundle. I feel like I must have a misconfiguration somewhere. Before I was able to bundle with microbundle-crl which we're moving from in favour of Webpack.
Here is my webpack.config.js file:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const DtsBundleWebpack = require('dts-bundle-webpack');
module.exports = {
mode: 'production',
entry: './src/index.tsx',
output: {
filename: 'index.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
},
resolve: {
extensions: ['.tsx', '.ts', '.json', 'jsx', '.js'],
},
devtool: 'inline-source-map',
module: {
rules: [
{
test: /\.(ts|tsx)$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{
test: /\.css$/,
use: [
MiniCssExtractPlugin.loader, //Extract css into files
'css-loader', // Turns css into commonjs
],
},
{
test: /\.pcss$/,
use: [
MiniCssExtractPlugin.loader,
'css-loader', // Turns css into commonjs
'postcss-loader'
]
},
],
},
plugins: [
new MiniCssExtractPlugin({ filename: 'randomcompany-components.css' }),
new DtsBundleWebpack({
name: '#randomcompany/components',
main: './dist/src/index.d.ts',
out: '../index.d.ts',
}),
],
};
My tsconfig.json is as follows:
{
"compilerOptions": {
"outDir": "dist",
"module": "esnext",
"lib": ["dom", "esnext"],
"types": ["react", "react-scripts"],
"moduleResolution": "node",
"jsx": "react",
"sourceMap": true,
"declaration": true,
"declarationDir": "dist",
"esModuleInterop": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"isolatedModules": true,
"preserveConstEnums": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"allowSyntheticDefaultImports": true,
"resolveJsonModule": true
},
"include": ["src", "src/lang"],
"exclude": ["node_modules", "dist", "src/stories"]
}
My enum is in this format:
export enum Test {
TestOne = "Test One",
TestTwo = "Test Two",
TestThree = "Test Three"
};
export default Test;
You should write it like below:
const Test = {
TestOne: "Test One",
TestTwo: "Test Two",
TestThree: "Test Three",
};
export default Test;
But in my opinion, using enum makes your bundle file a little bit heavy, just advise. use simple JavaScript objects.
I'm doing this:
import { GlideRecord } from "#nuvolo/servicenow-types/server/GlideRecord";
I have a file node_modules/#nuvolo/servicenow-types/server/GlideRecord.d.ts
It contains:
...
type GlideRecordConstructor = { new <T>(table: string): GlideRecord<T> };
type GlideRecord<T> = GlideRecordBase<T> & T;
declare const GlideRecord: GlideRecordConstructor;
export { GlideRecord };
If I run tsc it works, no errors
Webpack says:
Module not found: Error: Can't resolve '#nuvolo/servicenow-types/server/GlideRecord' in ...
Webpack config:
{
mode: "production",
//set name of record as the library name
output: {
filename: "file.js"
},
module: {
rules: [
{
test: /\.ts$/,
use: 'ts-loader',
//use: 'awesome-typescript-loader',
exclude: /node_modules/,
},
],
},
resolve: {
//modules: ['node_modules'],
extensions: [ '.ts', '.js' ], // Allows imports to work from .ts and .js
},
}
tsconfig.json:
{
"transpile": false,
"compilerOptions": {
"lib": ["es2015", "dom"],
"esModuleInterop": true,
"baseUrl": ".",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true
}
}
how do I fix this?
I've also created a GH issue here: https://github.com/nuvolo/sincronia/issues/138
This file checks out to be valid via TS, no more errors but during runtime, I get Unexpected token ':' on any of the TS I specified such as it immediately errors on function (err: string)
Here are my build and start scripts. I of course run build, then run start:
"start": "node --trace-warnings dist/server.ts",
"build": "NODE_ENV=production webpack -p --env=prod",
api.ts
const _ = require('lodash'),
companyTable = require('./shared/data/companies.json'),
countryTable = require('./shared/data/countries.json'),
compression = require('compression'),
express = require('express'),
expressApp = (module.exports = express()),
historyApi = require('connect-history-api-fallback'),
oneYear = 31536000;
expressApp.use(compression());
module.exports = expressApp
.on('error', function (err: string) {
console.log(err);
})
.get('/api/v1/countries', (res: any) => {
res.json(
countryTable.map((country: any) => {
return _.pick(country, ['id', 'name', 'images']);
})
);
})
server.ts
const app = require('./api.js');
const cluster = require('cluster'),
os = require('os'),
port = process.env.PORT || 8080;
console.log(port);
if (cluster.isMaster) {
for (let i = 0; i < os.cpus().length; i++) {
cluster.fork();
}
console.log('Ready on port %d', port);
} else {
app.listen(port, (err: string) => {
console.log(`express is listening on port ${port}`);
if (err) {
console.log('server startup error');
console.log(err);
}
});
}
tsconfig.json
{
"compilerOptions": {
/* Visit https://aka.ms/tsconfig.json to read more about this file */
"target": "es6", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */
"module": "es6", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */
"lib": ["es6"], /* Specify library files to be included in the compilation. */
"moduleResolution": "node",
"allowJs": true, /* Allow javascript files to be compiled. */
"checkJs": true, /* Report errors in .js files. */
"jsx": "react",
"noImplicitAny": true,
"sourceMap": true, /* Generates corresponding '.map' file. */
"outDir": "dist", /* Redirect output structure to the directory. */
"rootDir": "./", /* Specify the root directory of input files. Use to control the output directory structure with --outDir. */
"removeComments": true, /* Do not emit comments to output. */
"strict": true, /* Enable all strict type-checking options. */
"noUnusedLocals": true, /* Report errors on unused locals. */
"noUnusedParameters": true, /* Report errors on unused parameters. */
// "rootDirs": ["."], /* List of root folders whose combined content represents the structure of the project at runtime. */
"typeRoots": [
"node_modules/#types"
], /* List of folders to include type definitions from. */
"allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
"preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
// "resolveJsonModule": true,
"skipLibCheck": true, /* Skip type checking of declaration files. */
"forceConsistentCasingInFileNames": true
},
"include": [
"src"
],
"exclude": [
"/node_modules",
"/src/client/js/ink-config.js",
"**/test"
]
}
UPDATE
So someone pointed out the obvious. Asking why does my dist have a .ts file in it (server.ts) and api.ts. That's because I'm copying it over in my webpack.config.js:
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const TerserJSPlugin = require('terser-webpack-plugin');
const HtmlWebPackPlugin = require('html-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const CopyPlugin = require('copy-webpack-plugin');
const isProduction = process.env.NODE_ENV === 'production';
const html = () => {
return new HtmlWebPackPlugin({
template: path.resolve(__dirname, 'src/client', 'index.html'),
filename: 'index.html',
hash: true,
});
};
const copyAllOtherDistFiles = () => {
return new CopyPlugin({
patterns: [
{ from: 'src/client/assets', to: 'lib/assets' },
{ from: 'src/server.ts', to: './' },
{ from: 'src/api.ts', to: './' },
{ from: 'package.json', to: './' },
{ from: 'ext/ink-3.1.10/js/ink-all.min.js', to: 'lib/js' },
{ from: 'ext/ink-3.1.10/js/autoload.min.js', to: 'lib/js' },
{ from: 'ext/js/jquery-2.2.3.min.js', to: 'lib/js' },
{ from: 'ext/ink-3.1.10/css/ink.min.css', to: 'lib/css/ink.min.css' },
{ from: 'feed.xml', to: './' },
{
from: 'src/shared',
to: './shared',
globOptions: {
ignore: ['**/*suppressed.json'],
},
},
],
});
};
module.exports = {
entry: './src/client/index.tsx',
output: {
filename: 'scripts/app.[hash].bundle.js',
publicPath: '/',
path: path.resolve(__dirname, 'dist'),
},
resolve: {
extensions: ['.ts', '.tsx', '.js'],
},
devtool: 'inline-source-map',
devServer: {
writeToDisk: true,
port: 8080,
},
optimization: {
minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
splitChunks: {
cacheGroups: {
styles: {
name: 'styles',
test: /\.css$/,
chunks: 'all',
enforce: true,
},
},
},
},
module: {
rules: [
{
test: /\.(js)$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
},
},
{
test: /\.(tsx|ts)?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
{
test: /\.html$/,
use: [
{
loader: 'html-loader',
},
],
},
{
test: /\.less$/,
use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader'],
},
{
test: /\.css$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
options: {
hmr: process.env.NODE_ENV === 'development',
},
},
'css-loader',
],
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
loader: 'file-loader',
options: {
outputPath: 'lib/assets/fonts',
},
},
{
test: /\.(png|svg|jpg|gif)$/,
use: ['url-loader'],
},
],
},
plugins: isProduction
? [
new CleanWebpackPlugin(),
new MiniCssExtractPlugin({
filename: isProduction ? 'lib/css/main.[hash].css' : 'main.css',
}),
html(),
copyAllOtherDistFiles(),
]
: [new CleanWebpackPlugin(), html(), copyAllOtherDistFiles()],
};
So...I need to do something different. While I do need server.ts and api.ts during development, not sure how I can transpile then copy those two files over (ouside of the web bundle I create).
So I'm not entirely sure what the use case for copying over the files directly is - but let me answer by pointing out how you can achieve having the transpiled files in the output directory while still using the original .ts source file in development:
First, you can use ts-node-dev in development which helpfully allows you to run the original source files by transpiling on the fly so you can use it just as you would use the node binary, but on the source files rather than the emitted files. I use a command similar to this for development: NODE_ENV=development ts-node-dev --watch ./src/server.ts --transpileOnly ./src/server.ts
Then, for production, provided that you do not specify the noEmit option in your compiler options, TypeScript will transpile and emit files to the provided outDir. So, you can run these emitted files using the node binary: NODE_ENV=production node ./dist/server.js. This would allow you to remove the files under your source directory from your copy plugin, as TypeScript will transpile and emit the transpiled js in the directory for you
Edit (from comments): To include only the files which you want to be transpiled, you can specify those in include in your tsconfig:
include: ['./src/api.ts', './src/server.ts']
I am trying to make a React library using Typescript, Webpack and Babel however I am running into a problem. If I build then import the library into a React project then my import is 'undefined' (See the below error). I think this would be because in the bundle.js there is no module.exports for the variable that would represent my class there is only a __webpack_exports__["default"] = (ExampleComponent); (However I am unsure of what this does in practice so I could be wrong.)
I specifically got this error:
Error: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: undefined. You likely forgot to export your component from the file it's defined in, or you might have mixed up default and named imports.
What I have tried:
Changing the tsconfig target to es6 and module to commonjs
Changing the tsconfig target to es6 and module to esnext
Changing the tsconfig target to es5 and module to esnext
Changing the tsconfig target to esnext and module to esnext
Changing the tsconfig target to es6 and module to es6
Changing the tsconfig target to commonjs and module to es6
Importing the library as 'import * as ExampleComponent from ...' and 'import {ExampleComponent} from ...' (As intended) both times 'ExampleComponent' was undefined.
Versions:
babel-loader: ^8.1.0
Webpack: ^4.43.0
typescript: ^3.8.3
Code:
React Project:
import React from "react";
import { ExampleComponent } from "test-lib";
// This is always undefined
console.log(ExampleComponent);
function App() {
return <ExampleComponent />;
}
export default App;
Library Project:
index.ts:
import ExampleComponent from './ExampleComponent'
export { ExampleComponent }
ExampleComponent.tsx
import * as React from 'react'
import './ExampleComponent.css'
interface Props {
text: string
}
// prettier-ignore
const ExampleComponent: React.FC<Props> = ({ text }) => (
<h1 className="example-text">{text}</h1>
)
export default ExampleComponent
Library Configs:
tsconfig.json:
{
"compilerOptions": {
"outDir": "dist",
"module": "esnext",
"lib": ["dom", "esnext"],
"moduleResolution": "node",
"jsx": "react",
"sourceMap": true,
"declaration": true,
"esModuleInterop": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noImplicitAny": true,
"strictNullChecks": true,
"suppressImplicitAnyIndexErrors": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"allowSyntheticDefaultImports": true,
"target": "es5",
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"resolveJsonModule": true
},
"include": ["src", "tests"],
"exclude": ["node_modules", "dist", "example"]
}
.babelrc:
{
"presets": [
[
"#babel/preset-env",
{
"debug": true,
"useBuiltIns": "usage",
"corejs": 3
}
],
"#babel/preset-react",
"#babel/preset-typescript"
]
}
Webpack Config:
const path = require('path')
const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin')
module.exports = {
entry: {
bundle: './src/index.ts',
},
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
},
resolve: {
extensions: ['.tsx', '.ts', '.js', '.json'],
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.tsx?$/,
exclude: /node_modules/,
use: [{ loader: 'babel-loader' }, { loader: 'ts-loader' }],
},
{
test: /\.css$/,
loaders: ['style-loader', 'css-loader'],
},
{
test: /\.(gif|png|jpe?g|svg)$/,
use: [
'file-loader',
{
loader: 'image-webpack-loader',
options: {
disable: true,
},
},
],
},
{
test: /\.js$/,
enforce: 'pre',
loader: 'source-map-loader',
},
],
},
plugins: [new ForkTsCheckerWebpackPlugin()],
}
If you want to see the full code here is a link to the Github Repo.
Based on the comment from Scovy I was able to get this working by using the output.libraryTarget and output.globalObject output options.
Now my output entry in my webpack.base.config.js looks like this:
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
libraryTarget: 'umd',
globalObject: 'this',
},
Update:
The above change did not seam to work 100% of the time so I found a library called esm-webpack-plugin which ended up working perfectly.
So the final code for the output entry in the webpack config is:
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js',
library: 'LIB',
libraryTarget: 'var',
},
and I also added the plugin:
plugins: [new ForkTsCheckerWebpackPlugin(), new EsmWebpackPlugin()],