I am working on creating a webpack plugin. I have used typescript to code the plugin. I am trying to bundle the plugin code before I publish it on NPM. I am getting exception that my plugin class is not a constructor.
Please find below the directory structure:-
tsconfig.json:-
{
"compilerOptions": {
// Target latest version of ECMAScript.
"target": "es5",
// Specify module code generation: 'commonjs', 'amd', 'system', 'umd' or 'es2015'.
"module": "commonjs",
// Search under node_modules for non-relative imports.
"moduleResolution": "node",
// Process & infer types from .js files.
"allowJs": true,
// Don't emit; allow Babel to transform files.
"noEmit": false,
"pretty": true,
// Enable strictest settings like strictNullChecks & noImplicitAny.
"strict": true,
// Disallow features that require cross-file information for emit.
"isolatedModules": true,
// Import non-ES modules as default imports.
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"outDir": "dist/"
},
"include": [
"src"
],
"exclude": [
"dist",
"node_modules"
]
}
Webpack config:-
const path = require('path');
module.exports = {
name: 'log-stylizer-webpack-plugin',
entry: './src/index.ts',
output: {
filename: 'index.bundle.js',
path: path.resolve(__dirname, 'dist'),
},
mode: 'development',
target: 'node',
module: {
rules: [
{
test: /\.ts?$/,
use: 'ts-loader',
exclude: /node_modules/,
}
]
},
resolve: {
extensions: ['.ts']
}
};
In order to build a thing as a library with webpack, you have to specify the option output.libraryTarget to export things.
{
output: {
// ...
// `umd` is always a best choice in most cases
// since it would work for all kind of module styles
libraryTarget: 'umd',
}
}
Related
I'm setting app a new TypeScript/React Project using the following module https://www.npmjs.com/package/#adobe/leonardo-contrast-colors
Using node v16.17.0.
To start with I replicate the example in the README.md but the import doesn't work. Doing the following:
import { Theme, Color, BackgroundColor } from '#adobe/leonardo-contrast-colors';
returns:
Module '"#adobe/leonardo-contrast-colors"' has no exported member 'Theme'.
Module '"#adobe/leonardo-contrast-colors"' has no exported member 'Color'.
Module '"#adobe/leonardo-contrast-colors"' has no exported member 'BackgroundColor'.
Apparently '#adobe/leonardo-contrast-colors' leads to index.d.ts
and if I try to import the members like this:
import { Color } from "#adobe/leonardo-contrast-colors/color.mjs";
neither it works as I get:
Package path ./color.mjs is not exported from package /Users/.../package.json)
I see this open issue in the package repo: https://github.com/adobe/leonardo/issues/173
but backing to 1.0.0-alpha.13 turns out the same for me.
This is my tsconfig
{
"compilerOptions": {
"allowJs": true,
"esModuleInterop": true,
"target": "ES2015",
"jsx": "react",
"typeRoots": ["./node_modules/#types"],
"module": "ESNext",
"moduleResolution": "Node",
"skipLibCheck": true,
"allowSyntheticDefaultImports": true,
"sourceMap": true
},
"include": ["src/**/*.ts", "src/**/*.tsx"]
}
And webpack.config.js:
module.exports = (env, argv) => ({
...
module: {
rules: [
// Converts TypeScript code to JavaScript
{
test: /\.tsx?$/,
use: "ts-loader",
exclude: /node_modules/,
},
...
],
},
resolve: { extensions: [".tsx", ".ts", ".jsx", ".js"] },
...
});
Is this a problem with the package or my project cofiguration?
Thanks in advance
I am trying to use imagemin node package in my project. It is a es6 module and I am getting error while using it.
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module. with "type" as "module" in package.json
ReferenceError: require is not defined with "type" as "commonjs" in package.json
My webpack config:
export default env => {
return {
mode: env.production ? 'production' : 'development',
entry: {
main: './src/main.ts',
worker: './src/worker.ts'
},
target: ['node', 'es2019'],
devtool: env.production ? false : 'inline-source-map',
watch: !env.production,
resolve: {
extensions: ['.ts', '.js'],
alias: {
src: _resolve(process.cwd(), './src')
}
},
module: {
rules: [{
test: /\.ts$/,
include: _resolve(process.cwd(), "src"),
use: 'ts-loader',
exclude: [/node_modules/, /\.spec\.ts/, /\.e2e-spec\.ts/]
}],
},
externalsPresets: { node: true },
externals: [nodeExternals()],
output: {
filename: '[name].js',
path: OUTPUT_DIR,
clean: !!env.production,
devtoolModuleFilenameTemplate: 'file:///[absolute-resource-path]',
library: {
type: 'module'
}
},
optimization: {
minimize: false, //!!env.production
mangleExports: true,
minimizer: [new terserPlugin({
terserOptions: {
output: {
comments: false
},
keep_classnames: true,
},
extractComments: false,
})]
},
experiments: {
outputModule: true
}
};
};
My tsconfig:
{
"compilerOptions": {
"module": "ES2020",
"removeComments": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"allowSyntheticDefaultImports": true,
"target": "es2019",
"sourceMap": true,
"strict": true,
"baseUrl": ".",
"esModuleInterop": true,
"noImplicitAny": true,
"moduleResolution": "node",
"outDir": "../bin/server",
"typeRoots": [
"node_module/#types",
"./typings"
],
"types": [
"node",
"#types/jest"
]
},
"exclude": [
"node_modules"
]
}
When I try to "import" imagemin in one of my .ts file, webpack convert it to "require". I have also tried using import() but it doesn't work either.
I have made a repo on github
Is there a way to get es6 bundle (preferred) or use imagemin with commonjs bundle?
I couldn't found a way to bundle es6 format through webpack but i was able to use es6 module in commonjs system while bundling through webpack.
externals: [
nodeExternals({
allowlist: ['imagemin', 'imagemin-mozjpeg']
}),
async function ({ request }) {
if (request === 'imagemin' || request === 'imagemin-mozjpeg')
return `import ${request}`;
},
]
This is how i got imagemin to work.
Change your start script
"start": "node --experimental-modules src/index.mjs "
and In package.json Add
{
...
"type": "module",
...
}
Here is webpack.config.ts
// const path = require("path");
import path from "path";
import HtmlWebpackPlugin from "html-webpack-plugin";
import CopyWebpackPlugin from "copy-webpack-plugin";
import webpack from "webpack";
import WebpackDevServer from "webpack-dev-server";
declare module "webpack" {
interface Configuration {
devServer?: WebpackDevServer.Configuration;
}
}
const config: webpack.Configuration = {
mode: "development",
target: "web",
entry: ["regenerator-runtime/runtime", "./src/index.tsx"],
output: {
filename: "bundle.js",
path: path.join(__dirname, "build"),
publicPath: "/",
},
resolve: {
extensions: [".ts", ".tsx", ".js", ".css"],
alias: {
// add as many aliases as you like!
components: path.resolve(__dirname, "src/components"),
},
fallback: {
// path: require.resolve("path-browserify"),
fs: false,
assert: require.resolve("assert/"),
os: require.resolve("os-browserify/browser"),
constants: require.resolve("constants-browserify"),
},
},
devtool: "eval-cheap-source-map",
module: {
rules: [
{ test: /\.(ts|tsx)/, loader: "babel-loader", exclude: /node_modules/ },
{ test: /\.css$/, use: ["style-loader", "css-loader"] },
{
test: /\.(woff(2)?|ttf|eot)(\?v=\d+\.\d+\.\d+)?$/,
use: [
{
loader: "file-loader",
options: {
name: "[name].[contenthash].[ext]",
outputPath: "fonts/",
},
},
],
},
{
test: /\.svg$/,
use: [
{
loader: "svg-url-loader",
options: {
limit: 10000,
},
},
],
},
],
},
devServer: {
contentBase: path.join(__dirname, "build"),
historyApiFallback: true,
overlay: true,
},
plugins: [
new HtmlWebpackPlugin({
title: "esBUild",
template: "src/index.html",
}),
new CopyWebpackPlugin({
patterns: [{ from: "assets", to: "assets" }],
}),
new webpack.ProvidePlugin({
process: "process/browser",
Buffer: ["buffer", "Buffer"],
React: "react",
}),
],
};
export default config;
here is tsconfig.json:
{
"compilerOptions": {
// The standard typing to be included in the type checking process.
"lib": ["dom", "dom.iterable", "esnext"],
// Whether to allow JavaScript files to be compiled.
"allowJs": true,
//This allows default imports from modules with no default export in the type checking process.
"allowSyntheticDefaultImports": true,
// Whether to skip type checking of all the type declaration files (*.d.ts).
"skipLibCheck": true,
// This enables compatibility with Babel.
"esModuleInterop": true,
"strict": true,
// Ensures that the casing of referenced file names is consistent during the type checking process.
"forceConsistentCasingInFileNames": true,
// This allows modules to be in .json files which are useful for configuration files.
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"module": "es6",
"target": "es5",
"sourceMap": true,
"noEmit": true,
"jsx": "react",
"baseUrl": "src",
"paths": {
"components": ["components/*"]
}
},
"include": ["src"]
}
THis is the error I get :
import path from "path";
^^^^^^
SyntaxError: Cannot use import statement outside a module
I googled it and see some people suggest adding "type":"module", it did not work.
in tsconfig.json
"module": "es6" /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */,
I tried each option but this did not work neither.
If I discard the typescript configuration, set up webpack with common.js, it works
Also .babelrc
{
"presets": [
"#babel/preset-react",
"#babel/preset-env",
"#babel/preset-typescript"
],
"plugins": [
"#babel/plugin-proposal-class-properties",
"#babel/plugin-proposal-object-rest-spread"
]
}
In my case I have to change to "module": "commonjs", inside tsconfig.json. Refer https://www.typescriptlang.org/tsconfig#module
In my case I have to install typescript types of plugins (vscode suggested it after restart the ide).
For example:
For dotenv-webpack package, I installed #types/dotenv-webpack.
Please refer to this section of the Webpack configuration documentation:
The above sample assumes version >= 2.7 or newer of TypeScript is used with the new esModuleInterop and allowSyntheticDefaultImports compiler options in your tsconfig.json file.
Note that you'll also need to check your tsconfig.json file. If the module in compilerOptions in tsconfig.json is commonjs, the setting is complete, else webpack will fail with an error. This occurs because ts-node does not support any module syntax other than commonjs.
There are three solutions to this issue:
Modify tsconfig.json.
Modify tsconfig.json and add settings for ts-node.
Install tsconfig-paths.
You've set the correct values for "esModuleInterop" and "allowSyntheticDefaultImports" in your tsconfig.json, so, to get rid of the error, you should do one of the above three options.
The first one suggests you to change the "module" compiler option's value to "commonjs".
The second one allows you to keep the "module" option's value as is, but you should add the settings for ts-node in your tsconfig.json.
The third one requires additional package installation and a separate TS configuration file.
I am creating a component library to be consumed by a secondary Node app (both using Typescript). In this component library, we have a number of ambient modules to help with typing/loading picture files, eg:
declare module "*.png" {
const content: string;
export default content;
}
as well as other types that are extended off of existing but incomplete types from 3rd party libraries... eg:
import * as vc from "victory-core";
import * as vl from "victory-label";
declare module "victory-core" {
export interface CallbackArgs extends vc.CallbackArgs {
index: number;
}
}
declare module "victory" {
export interface VictoryLabelProps extends vl.VictoryLabelProps {
stringTicks?: string[];
index?: number;
}
}
This library is then compiled and built using Rollup, and consumed by the secondary app. The issue is that these types are not available to the consumer app - ie, if a component is trying to pass in a stringTicks arg as part of VictoryLabelProps, it will not be recognized as a valid prop.
Similarly with the .png module, I cannot load up a png file in my consumer app unless I literally copy and paste the .d.ts file and explicitly add it as part of my consumer app
Below is my tsconfig for my component library:
{
"compilerOptions": {
"declaration": true,
"declarationDir": "./dist",
"outDir": "./dist",
"rootDir": "./src",
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"baseUrl": ".",
"typeRoots": [
"src/types",
"node_modules/#types"
],
},
"exclude": ["node_modules", "dist"],
"include": ["src/**/*"],
}
(I tried adding typeRoots and baseUrl based on https://elfi-y.medium.com/typescript-ambient-module-8816c9e5d426)
and my rollup.config:
{
input: "src/index.ts",
output: [
{
dir: "dist",
format: "cjs",
sourcemap: true,
},
],
external: ["fs"],
plugins: [
peerDepsExternal(),
commonjs({
include: "node_modules/**",
}),
resolve(),
babel({
exclude: "node_modules/**",
babelHelpers: "bundled",
extensions: [...DEFAULT_EXTENSIONS, ".ts", ".tsx"],
presets: [["#babel/preset-react", { runtime: "automatic" }]],
}),
typescript(),
json(),
image(),
url({
include: ["**/*.woff", "**/*.woff2"],
limit: Infinity,
}),
],
};
Any help is appreciated!!
You need to include the types field in the package.json of your library. The field should contain the path to the .d.ts directory or file.
{
"name": "awesome",
"author": "Vandelay Industries",
"version": "1.0.0",
"main": "./lib/main.js",
"types": "./lib/main.d.ts"
}
More info:Including declarations in your package
Regarding to the webpack docs for external libraries and nodejs, there is the information that one should be able to import node modules. This works perfectly unless I want to import http2. It prints the following error:
ERROR in ./src/index.ts
Module not found: Error: Can't resolve 'http2' in 'absolutepath/to/src'
The entry typescript file simplified looks like this:
import { readFileSync } from 'fs';
import { createSecureServer } from 'http2';
const server = createSecureServer({...});
And the webpack configuration file looks like follows:
const path = require('path');
module.exports = {
entry: './src/index.ts',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'index.js'
},
node: {
global: true,
process: true,
fs: 'empty',
http2: 'empty'
},
module: {
rules: [
{ test: /\.ts$/, use: 'ts-loader' }
]
},
resolve: {
extensions: [".ts", ".tsx", ".js"],
modules: [path.resolve(__dirname, '/src'), 'node_modules/'],
descriptionFiles: ['package.json']
},
mode: 'production'
}
And the tsconfig.json
{
"compileOnSave": false,
"compilerOptions": {
"experimentalDecorators": true,
"target": "es5",
"module": "commonjs",
"emitDecoratorMetadata": true,
"outDir": "dist",
"declaration": false,
"sourceMap": true,
"removeComments": true,
"moduleResolution": "node",
"strict": true,
"noImplicitAny": false,
"typeRoots": [
"node_modules/#types"
],
"lib": [
"es2017"
]
}
}
E.g. importing fs works without errors. I also have seen the node-libs-browser plugin where the http2 module is not listed. But I don't want to use http2 within the browser but just for bundling my backend application. Any suggestions or ideas?
Thanks and cheers!