I am building a library that uses ES6 modules and contains classes. If instead of bundling, I just point the package.json "main" to the source code, all works well! I can import the library into an application and it works wonderfully.
Once I bundle the application using WebPack and point the "main" to the packaged bundle, nothing works and I am left scratching what little hair I have left on my head.
Here is the error I am getting:
notablet__WEBPACK_IMPORTED_MODULE_3__.Notablet is not a constructor
Here is my package.json
{
"name": "notablet",
"version": "4.7.0",
"main": "lib/index.js",
"type": "module",
"scripts": {
"test": "npx mocha ./test/**/*.test.js",
"coverage": "c8 --reporter=text --all npm run test",
"build": "webpack --config webpack.config.js"
},
"license": "MIT",
"devDependencies": {
"c8": "^7.12.0",
"chai": "^4.3.6",
"clean-webpack-plugin": "^4.0.0",
"css-loader": "^6.7.1",
"jsdom": "^20.0.0",
"mocha": "^10.0.0",
"sinon": "^14.0.0",
"style-loader": "^3.3.1",
"webpack": "^5.73.0",
"webpack-cli": "^4.10.0"
}
}
And here is my webpack.config.js:
import path from 'path';
import {fileURLToPath} from 'url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
const config = {
mode: 'development',
devtool: false,
entry: './src/Notablet.js',
output: {
path: path.resolve(__dirname, 'lib'),
filename: "index.js",
library: "notablet"
},
module: {
rules: [
{
test: /\.css$/i,
use: ["style-loader", "css-loader"],
},
],
}
};
export default config;
Note... I did change the "mode" above from "development" to "production", but got the same error after bundling and using.
Here is relevant parts of my Notablet.js file:
import { Queue } from './Queue.js';
// Themes
import style from './style.css'; // assert { type: "css" };
import light from './theme/light.css';
import dark from './theme/dark.css';
import elegant from './theme/elegant.css';
import fantasy from './theme/fantasy.css';
import robot from './theme/robot.css';
export class Notablet {
constructor(conf = {}, queue = new Queue()) {
this.queue = queue;
var config = {
backgroundColor: 'black',
color: '#ffffff',
theme : 'light'
};
this.config = {...config, ...conf};
this.loadTheme();
}
/**
* Loads the theme identified in the configuration object along with the base stylesheet
*/
loadTheme() {
var theme = this.getTheme(this.config.theme)
var sheet = new CSSStyleSheet();
sheet.replace(theme);
var baseSheet = new CSSStyleSheet();
baseSheet.replace(style);
document.adoptedStyleSheets = [baseSheet, sheet];
}
getTheme(theme = 'light') {
var ret = light;
switch(theme) {
case "dark":
ret = dark;
break;
case "elegant":
ret = elegant;
break;
case "fantasy":
ret = fantasy;
break;
case "robot":
ret = robot;
break;
}
return ret;
}
}
The error appears to be thrown in my application when I call let nt = new Notablet()
Notablet appears to be a valid class in ES6 and it has a constructor. My assumption is Webpack needs to be configured to handle the ES6 module somehow, but I understood I just needed to change my package.json "type" to "module".
Any help is greatly appreciated!
Related
I am trying to use vue-loader with my SPA VUE APP, And I'm getting the following error.
ERROR in ./app2.vue
Module build failed (from ./node_modules/vue-loader/dist/index.js):
TypeError: Cannot read properties of undefined (reading 'styles')
at Object.loader (/Users/daniel.bachnov/docker/qhs3-admin/frontend/node_modules/vue-loader/dist/index.js:70:34)
# ./main.js 1:0-29 14:8-11
webpack 5.74.0 compiled with 1 error and 3 warnings in 3312 ms
For eliminating app code noise, I created very simple component app2.vue:
And tried to connect it to my main.js entry point file.
<script>
export default {
data() {
return {
count: 0
}
}
}
</script>
<template>
<button #click="count++">You clicked me {{ count }} times.</button>
</template>
main.js
import App from './app2.vue';
import Router from './router/router.js';
import Store from './store/index.js';
Vue.use(Vuetify)
Vue.use(VueRouter);
const app = new Vue({
router: Router.router,
store: Store,
el: '#app',
vuetify: new Vuetify(),
components: {
App,
}
});
webpack.config.js:
const path = require('path');
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
mode: 'production',
entry: './main.js',
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, './../src/public/dist/'),
publicPath: "/dist/"
},
module: {
rules: [
{
test: /\.vue$/,
loader: 'vue-loader'
}
]
},
plugins: [
// make sure to include the plugin!
new VueLoaderPlugin()
]
};
package.json
{
"name": "app",
"version": "1.0.0",
"description": "app",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"watch": "webpack --watch",
"build": "webpack"
},
"author": "daniel bach",
"license": "ISC",
"dependencies": {
"#mdi/js": "^5.9.55",
"#vue/composition-api": "1.0.4",
"#vuetify/cli-plugin-utils": "^0.0.9",
"apexcharts": "^3.27.3",
"core-js": "^3.6.5",
"vue": "^2.6.11",
"vue-apexcharts": "^1.6.2",
"vue-router": "^3.2.0",
"vuetify": "^2.4.0",
"vuex": "^3.4.0",
"vue-loader": "^17.0.0"
},
"devDependencies": {
"vue-loader": "^17.0.0",
"vue-template-compiler": "^2.7.13",
"webpack": "^5.74.0",
"webpack-cli": "^4.10.0"
},
"keywords": []
}
Do you have any idea why I keep getting this error?
vue-loader 16+ isn't compatible with vue 2.x
The vue-template-compiler / #vue/sfc-compiler has the following API in vue 2.7 (and 2.6):
https://github.com/vuejs/vue/blob/ca11dc6a86f26accc893c1ce5b611dc84a2e7c2d/packages/compiler-sfc/src/parse.ts#L33
for vue 3, the api changes, and the vue-loader also changes accordingly in 16+: https://github.com/vuejs/vue-loader/blob/1b1a195612f885a8dec3f371edf1cb8b35d341e4/src/index.ts#L92
So you need to use vue-loader 15.x
I encountered a similar issue once.Try reinstalling webpack npm install webpack#5.74.0 --save . It should work. If however it didn't, try lowering the version a bit.
Also try to:
delete node_modules folder and package-lock.json
run npm install again
I have a class View that I am importing and then extending it with galleryView .. Then I import the final galleryView into controller.js.. Somewhere along this path I am doing something wrong as I get this error..
Uncaught TypeError: Super expression must either be null or a function
But I can't figure out what I am doing wrong.. is it babel or webpack or my code?
Here's my webpack config file for development..
// 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: /\.m?js$/,
exclude: /(node_modules|bower_components)/,
use: {
loader: "babel-loader",
options: {
presets: ["#babel/preset-env"],
},
},
},
],
},
};
Here's the View Class
class View {
// _data;
constructor() {
this.data;
}
// UPDATED for ELEMENT
render(data) {
if (!data) return console.log("No data!!");
this.data = data;
const markup = this.generateMarkup();
this.parentElement.insertAdjacentElement("afterbegin", markup);
}
}
export default new View();
Here's the extended galleryView
import View from "./view.js";
class galleryView extends View {
constructor() {
super();
this.parentElement = document.getElementById("gallery");
this.errorMessage = "some error message";
this.message = "some other message";
}
generateMarkup() {
return `
<section id="gallery" class="gallery-content">
<p>some text here</p>
</section>
`;
}
}
export default new galleryView();
Here's the opening lines for controller.js where I think the problem occurs (I could be wrong)
import "./../css/main.scss";
import galleryView from "./view/galleryView.js";
// GALLERY AND MORE ....
And here's my package.json
{
"name": "brahma-gallery",
"version": "1.0.0",
"description": "The frontend views for Brahma's Gallery",
"scripts": {
"start": "webpack serve --open --config webpack.dev.js ",
"build": "webpack --config webpack.prod.js"
},
"author": "Alim Bolar",
"license": "ISC",
"devDependencies": {
"#babel/core": "^7.14.3",
"#babel/preset-env": "^7.14.4",
"babel-loader": "^8.2.2",
"css-loader": "^5.2.6",
"file-loader": "^6.2.0",
"html-loader": "^2.1.2",
"html-webpack-plugin": "^5.3.1",
"mini-css-extract-plugin": "^1.6.0",
"node-sass": "^6.0.0",
"optimize-css-assets-webpack-plugin": "^6.0.0",
"sass-loader": "^11.1.1",
"style-loader": "^2.0.0",
"webpack": "^5.38.1",
"webpack-cli": "^4.7.0",
"webpack-dev-server": "^3.11.2"
},
"dependencies": {
"clean-webpack-plugin": "^4.0.0-alpha.0"
}
}
Please advise if you can figure out what I could be doing wrong.. I've googled and searched for related issues and read up some confusing stuff on babel not allowing some sort of exports etc.. but I am very new to babel and don't really know which of the related posts to follow..
Any help or guidance would be appreciated.
export default new View();
should be
export default View;
or you can directly do
export default class View {
When you make a class and extend a class, you extend the class itself, e.g.
class View {}
class galleryView extends View {}
but right now you are incorrectly doing
class View {}
class galleryView extends (new View()) {}
where you extend an instance of the class, which does not make sense.
I think that I'm having a problem with imports being redeclared within my transpiled index.js file
I'm transpiling some react es6 components into a single index.js file. These components are then imported into another projects by running 'npm install /path/to/myComponents'
When I import these components into my main project, I get the error
SyntaxError: Identifier '_interopRequireDefault' has already been declared
...
> 53 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
...
This line does show up multiple times in my index.js in a chunk of code that looks like this
var _react = _interopRequireDefault(require("react"));
var _componentX = require("./ComponentX.js");
var _propTypes = _interopRequireDefault(require("prop-types"));
var _this = void 0;
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
var ComponentY = function ComponentY(props) {
I want to fix how I transpile the code so that this either doesn't happen, or I just ignore redeclarations, they are all the same anyway.
my src folder, where my react components are, contains an index.js file, and a components folder with 3 Components inside it. Each of these component contains
import React from 'react';
import propTypes from 'prop-types'
And two of them import the third component
Possible solution
I'm pretty sure the solution involves changing something about the line "build": "./node_modules/.bin/babel src --out-file index.js". But I don't know how to do this.
These are the files within my Components folder, not my main project folder(which imports the components folder.)
.babelrc
{
"presets": ["#babel/preset-env", "#babel/preset-react"],
"plugins": [
[
"#babel/plugin-proposal-class-properties",
{
"loose": true
}
]
]
}
package.json
{
"name": "myComponent",
"version": "1.0.0",
"scripts": {
"build": "./node_modules/.bin/babel src --out-file index.js"
},
"dependencies": {},
"peerDependencies": {
"react": "^16.6.1",
"react-dom": "^16.6.3"
},
"devDependencies": {
"#babel/cli": "^7.5.5",
"#babel/core": "^7.5.5",
"#babel/plugin-proposal-class-properties": "^7.5.5",
"#babel/preset-env": "^7.5.5",
"#babel/preset-react": "^7.0.0",
"react": "^16.8.6",
"react-dom": "^16.8.6"
}
}
webpack.config.js
var path = require('path');
module.exports = {
entry: './src/index.js',
output: {
path: path.resolve(__dirname, 'build'),
filename: 'index.js',
libraryTarget: 'commonjs2' // THIS IS THE MOST IMPORTANT LINE! :mindblow: I wasted more than 2 days until realize this was the line most important in all this guide.
},
module: {
rules: [
{
test: /\.js$/,
include: path.resolve(__dirname, 'src'),
exclude: /(node_modules|bower_components|build)/,
use: {
loader: 'babel-loader',
options: {
presets: ['env']
}
}
}
]
},
externals: {
'react': 'commonjs react' // this line is just to use the React dependency of our parent-testing-project instead of using our own React.
}
};
I am trying to provide some sort of cross compatibility with IE 10. I have used the Babel Polyfill to get past a Promise exception for IE 11, but for IE 10 I am getting exceptions for Set and Weakmap which babel polyfill should correct as it was my understanding that these were included as well.
This was my first React/React-static project, so flying by the seat of my pants to be honest so hope someone can help/explain things in a simple clear fashion.
FYI: Set is undefined in the main.js file produced by react-static build. And Weakmap is found in the hot-reloader module which is only a problem in dev mode.
My App.js file:
import "babel-polyfill";
import React from "react";
import { Router, Link } from "react-static";
import { hot } from "react-hot-loader";
import Routes from "react-static-routes";
import "./sass/app.scss";
import "./sass/_base.scss";
import "./sass/_layout.scss";
import "./sass/_utilities.scss";
import "./sass/main.scss";
import "./sass/_components.scss";
const App = () => (
<Router>
<div>
<Routes />
</div>
</Router>
);
export default hot(module)(App);
My static.config.js file:
import ExtractTextPlugin from "extract-text-webpack-plugin";
export default {
getSiteData: () => ({
title: "React Static"
}),
getRoutes: async () => {
// const { data: posts } = await axios.get(
// "https://jsonplaceholder.typicode.com/posts"
// );
return [
{
path: "/",
component: "src/containers/Home"
},
{
path: "/about",
component: "src/containers/About"
},
{
path: "/services",
component: "src/containers/Services"
},
{
path: "/cases",
component: "src/containers/Cases"
},
{
path: "/process",
component: "src/containers/Process"
},
{
path: "/contact",
component: "src/containers/Contact"
},
{
path: "/contactsent",
component: "src/containers/Contactsent"
},
{
is404: true,
component: "src/containers/404"
}
];
},
webpack: (config, { defaultLoaders, stage }) => {
let loaders = [];
if (stage === "dev") {
loaders = [
{ loader: "style-loader" },
{ loader: "css-loader" },
{ loader: "sass-loader" }
];
} else {
loaders = [
{
loader: "css-loader",
options: {
importLoaders: 1,
minimize: stage === "prod",
sourceMap: false
}
},
{
loader: "sass-loader",
options: { includePaths: ["src/", "src/sass/"] }
}
];
// Don't extract css to file during node build process
if (stage !== "node") {
loaders = ExtractTextPlugin.extract({
fallback: {
loader: "style-loader",
options: {
sourceMap: false,
hmr: false
}
},
use: loaders
});
}
}
config.module.rules = [
{
oneOf: [
{
test: /\.s(a|c)ss$/,
use: loaders
},
defaultLoaders.cssLoader,
defaultLoaders.jsLoader,
defaultLoaders.fileLoader
]
}
];
return config;
}
};
My package.json:
{
"name": "react-static-example-basic",
"version": "1.0.1",
"main": "index.js",
"license": "MIT",
"scripts": {
"start": "react-static start",
"stage": "react-static build --staging",
"build": "react-static build",
"serve": "serve dist -p 3000"
},
"dependencies": {
"axios": "^0.16.2",
"core-js": "^3.0.1",
"es6-promise": "^4.2.6",
"promise-polyfill": "8.1.0",
"raf": "^3.4.1",
"react": "^16.0.0",
"react-dom": "^16.0.0",
"react-router": "^4.2.0",
"react-spring": "^8.0.5",
"react-static": "^5.9.7"
},
"devDependencies": {
"babel-polyfill": "^6.26.0",
"eslint-config-react-tools": "1.x.x",
"extract-text-webpack-plugin": "^3.0.2",
"node-sass": "^4.7.2",
"sass-loader": "^6.0.6",
"serve": "^6.1.0"
}
}
It may be worth trying to separately instal core-js include such modules in the assembly:
npm i --save core-js
import "core-js/es/set";
import "core-js/es/weak-map";
If that doesn't help try use polyfill.io:
Add yor html it:
<script crossorigin="anonymous" src="https://polyfill.io/v3/polyfill.min.js?features=WeakMap%2CWeakSet%2CSet"></script>
Not familiar with react-static as such, but from what I experienced with my projects with react and webpack:
the babel polyfill needs to go into the html page as a first script tag, and could not be packaged as part of webpack (I do not recall the exact reasons)
On projects not involving babel I had success convincing IE10 to play ball using: https://github.com/paulmillr/es6-shim
How can I import markdown files as strings in Next.js to work on client and server side?
You can configure your Next.js webpack loaders to load markdown files and return them as strings, for example:
docs/home.md
# Home
This is my **awesome** home!
pages/index.js
import React from 'react';
import markdown from '../docs/home.md';
export default () => {
return (
<div>
<pre>{markdown}</pre>
<small><i>Import and render markdown using Next.js</i></small>
</div>
);
};
package.json
{
"name": "example",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"file-loader": "^1.1.6",
"next": "^4.2.1",
"raw-loader": "^0.5.1",
"react": "^16.2.0",
"react-dom": "^16.2.0"
}
}
next.config.js
module.exports = {
webpack: (config) => {
return Object.assign({}, config, {
externals: Object.assign({}, config.externals, {
fs: 'fs',
}),
module: Object.assign({}, config.module, {
rules: config.module.rules.concat([
{
test: /\.md$/,
loader: 'emit-file-loader',
options: {
name: 'dist/[path][name].[ext]',
},
},
{
test: /\.md$/,
loader: 'raw-loader',
}
]),
}),
});
}
};
When running:
$ npm run dev
Something like this would appear:
With the markdown string you can do whatever you would like. For example, process it with marksy.
Quicker and "Next.js way" is to use plugin next-mdx
Documentation: https://github.com/vercel/next.js/tree/canary/packages/next-mdx
// next.config.js
const withMDX = require('#zeit/next-mdx')({
extension: /\.mdx?$/
})
module.exports = withMDX({
pageExtensions: ['js', 'jsx', 'mdx']
})
Just install raw-loader
npm install --save raw-loader
then edit your next.config.js
webpack: (config) => {
config.module.rules.push({
test: /\.md$/,
use: 'raw-loader',
});
return config;
},
Updates: emit-file-loader not strictly required, raw-loader deprecated in favor of asset modules
Some updates to https://stackoverflow.com/a/47954368/895245 possibly due to newer developments:
asset modules superseded raw-loader: https://stackoverflow.com/a/47954368/895245 No need to install any extra packages for that anyomore
emit-file-loader does not seem necessary anymore, not sure if it was needed, or if it is for something more specialized
so we can simplify things slightly to:
pages/index.js
import world from '../world.md'
export default function IndexPage() {
return <div>hello {world}</div>
}
next.config.js
module.exports = {
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
config.module.rules.push(
{
test: /\.md$/,
// This is the asset module.
type: 'asset/source',
}
)
return config
},
}
package.json
{
"name": "test",
"version": "1.0.0",
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start"
},
"dependencies": {
"next": "12.2.0",
"react": "17.0.2",
"react-dom": "17.0.2"
}
}
world.md
my md world
Getting it to work from Typescript
Unfortunately boch raw-loader and asset modules require a bit more work from typescript: https://github.com/webpack-contrib/raw-loader/issues/56#issuecomment-423640398 You have to create a file:
global.d.ts
declare module '*.md'
Otherwise the import will fail with:
Type error: Cannot find module '../world.md' or its corresponding type declarations.
Full example:
global.d.ts
declare module '*.md'
pages/index.tsx
import world from '../world.md'
export default function IndexPage() {
const what: string = 'my'
// Would fail on build as desired.
// const what2: int = 'world2'
return <div>hello {what} {world}</div>
}
next.config.js
module.exports = {
webpack: (config, { buildId, dev, isServer, defaultLoaders, webpack }) => {
config.module.rules.push(
{
test: /\.md$/,
type: 'asset/source',
}
)
return config
},
}
package.json
{
"private": true,
"scripts": {
"dev": "next",
"build": "next build",
"start": "next start",
"type-check": "tsc"
},
"dependencies": {
"next": "v12.2.0",
"react": "17.0.2",
"react-dom": "17.0.2"
},
"devDependencies": {
"#types/node": "12.12.21",
"#types/react": "17.0.2",
"#types/react-dom": "17.0.1",
"typescript": "4.0"
}
}
world.md
my md world