I have a Rails 6 application with Webpacker. Node packages have been successfully installed with yarn.
The application works locally both in development and production modes with Puma server. But when calling the website on our virtual host, Phusion Passenger fails loading the Bootstrap 4 JavaScript part:
/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:21178
var e = i.default.fn.jquery.split(' ')[0].split('.');
^
TypeError: Cannot read property 'jquery' of undefined
at Object.jQueryDetection (/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:21178:32)
at a (/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:21183:9)
at Object.<anonymous> (/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:22435:56)
at n (/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:8:17)
at Module.<anonymous> (/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:18176:7)
at Module.<anonymous> (/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:18179:7)
at n (/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:8:17)
at /var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:26:98
at Object.<anonymous> (/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:27:2)
at Module._compile (internal/modules/cjs/loader.js:1085:14)
app/javascript/packs/application.js:
// This file is automatically compiled by Webpack, along with any other files
// present in this directory. You're encouraged to place your actual application logic in
// a relevant structure within app/javascript and only use these pack files to reference
// that code so it'll be compiled.
console.log('Webpacker: START application.js');
require('#rails/ujs').start();
require('turbolinks').start();
require('#rails/activestorage').start();
require('channels');
require('jquery');
// Uncomment to copy all static images under ../images to the output folder and reference
// them with the image_pack_tag helper in views (e.g <%= image_pack_tag 'rails.png' %>)
// or the `imagePath` JavaScript helper below.
//
// const images = require.context('../images', true)
// const imagePath = (name) => images(name, true)
// #################### Proprietary configuration ####################
// JAVASCRIPT LIBRARIES
import 'popper.js';
import 'bootstrap';
import '#fortawesome/fontawesome-free';
// CSS OF USED LIBRARIES
import 'stylesheets/application';
// datetime picker
// load "moment" globally to avoid:
// "Error: Tempus Dominus Bootstrap4's requires moment.js. Moment.js must be included before Tempus Dominus Bootstrap4's JavaScript."
// See https://stackoverflow.com/questions/49580266/tempus-dominus-bootstrap4-requires-moment-js-datetime-picker
global.moment = require('moment');
require('moment/locale/de');
// If you require timezone data (see moment-timezone-rails for additional file options)
// import "moment-timezone-with-data"
require('tempusdominus-bootstrap-4');
console.log('Webpacker: END application.js');
config/webpack/environments.js (don't know what's correct here):
const { environment } = require('#rails/webpacker')
const webpack = require('webpack');
environment.plugins.prepend('Provide', // append
new webpack.ProvidePlugin({
$: 'jquery/src/jquery',
jQuery: 'jquery/src/jquery' // ,
// Popper: ['popper.js', 'defaults']
})
);
module.exports = environment
package.json:
{
"name": "myapp",
"private": true,
"dependencies": {
"#fortawesome/fontawesome-free": "^5.15.4",
"#popperjs/core": "^2.10.1",
"#rails/activestorage": "^6.1.4-1",
"#rails/ujs": "^6.1.4-1",
"#rails/webpacker": "5.4.3",
"bootstrap": "4.6.0",
"jquery": "^3.6.0",
"moment": "^2.29.1",
"moment-timezone": "^0.5.33",
"popper.js": "^1.16.1",
"tempusdominus-bootstrap-4": "^5.39.0",
"tempusdominus-core": "^5.19.0",
"turbolinks": "^5.2.0",
"webpack": "^4.46.0",
"webpack-cli": "^3.3.12"
},
"devDependencies": {
"webpack-dev-server": "^3"
}
}
When I use
if (typeof window !== "undefined") {
require('popper.js');
require('bootstrap');
require('#fortawesome/fontawesome-free');
}
like in Trying to import Bootstrap on Next.JS but says "TypeError: Cannot read property 'jquery' of undefined", I get another error:
/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:1785
return window.document;
^
ReferenceError: window is not defined
at Object.<anonymous> (/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:1785:7)
at Object.<anonymous> (/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:1786:7)
at n (/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:8:17)
at Object.<anonymous> (/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:6524:10)
at n (/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:8:17)
at Object.<anonymous> (/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:1682:110)
at Object.<anonymous> (/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:1772:8)
at n (/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:8:17)
at Object.<anonymous> (/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:1860:7)
at n (/var/www/vhosts/mydomain.com/httpdocs/myapp/public/packs/js/application-2432a12b5b63094eb637.js:8:17)
What am I missing?
Rails applications with Webpacker must not run as Node.js application additionally, although there are some Node packages used with Webpacker. They are only for client-side.
Phusion Passenger on the virtual host was configured not to load frequent application changes of all my numerous trial fixes. That's why the error didn't disappear when I tried the above solution weeks ago already ;-)
https://stackoverflow.com/questions/60198141/trying-to-import-bootstrap-on-next-js-but-says-typeerror-cannot-read-property was correct. Just had to wrap ALL Javascript library loads in application.js into condition:
if (typeof window !== "undefined")
Related
When exporting a function with more than 1 parameter (2 or more) it throws the following error, which basically says there is an issue with the way we import curry.js. I am attaching an example and package versions below.
Error:
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: path/to/node_modules/rescript/lib/es6/curry.js
require() of ES modules is not supported.
require() of /path/to/node_modules/rescript/lib/es6/curry.js from /path/to/src/demo.gen.ts is an ES module file as it is a .js file whose nearest parent package.json contains "type": "module" which defines all .js files in that package scope as ES modules.
Instead rename curry.js to end in .cjs, change the requiring code to use import(), or remove "type": "module" from /path/to/node_modules/rescript/lib/es6/package.json.
at new NodeError (node:internal/errors:329:5)
at Module._extensions..js (node:internal/modules/cjs/loader:1109:13)
at Object.require.extensions.<computed> [as .js] (/path/to/node_modules/ts-node/src/index.ts:851:44)
at Module.load (node:internal/modules/cjs/loader:972:32)
at Function.Module._load (node:internal/modules/cjs/loader:813:14)
at Module.require (node:internal/modules/cjs/loader:996:19)
at require (node:internal/modules/cjs/helpers:92:18)
at Object.<anonymous> (/path/to/src/demo.gen.ts:6:1)
at Module._compile (node:internal/modules/cjs/loader:1092:14)
at Module.m._compile (/path/to/node_modules/ts-node/src/index.ts:858:23)
Example
demo.res
#genType
let helloWord = (firstName: string, lastName: string): unit => {
Js.log("Hello " ++ firstName ++ " " ++ lastName)
}
demo.bs.js
// Generated by ReScript, PLEASE EDIT WITH CARE
'use strict';
function helloWord(firstName, lastName) {
console.log("Hello " + firstName + " " + lastName);
}
exports.helloWord = helloWord;
/* No side effect */
demo.gen.ts
/* TypeScript file generated from demo.res by genType. */
/* eslint-disable import/first */
// #ts-ignore: Implicit any on import
import * as Curry__Es6Import from 'rescript/lib/es6/curry.js';
const Curry: any = Curry__Es6Import;
// #ts-ignore: Implicit any on import
import * as demoBS__Es6Import from './demo.bs';
const demoBS: any = demoBS__Es6Import;
export const helloWord: (firstName:string, lastName:string) => void = function (Arg1: any, Arg2: any) {
const result = Curry._2(demoBS.helloWord, Arg1, Arg2);
return result
};
package.json
{
"ts-node": "^10.2.1",
"gentype": "^4.1.0",
"rescript": "^9.1.4",
"typescript": "^3.9.6"
}
Node Version
$ node -v
v15.11.0
OS
Manjaro Linux
After taking a look at this file in genType: https://github.com/rescript-association/genType/blob/fb6201266558a64d62441f7ac0d8d6652456397a/src/Config_.ml
I found this option
{
"gentypeconfig": {
"module": "commonjs",
}
}
setting that solves the issue :D
I could not found it anywhere else in rescript docs unfortunately :(
Background
I am currently in the process of migrating the backend of my project to ES6 via babel and am running into an error that seems to be related to a short-hand assignment that is not working anymore? I am not familiar with babel. Might be that I am not seeing something super obvious here.
Problem
now when trying to run my app in dev via yarn start I am seeing the following error (simplified example) this did work prior to setting up babel (I am on node.js 13.13.0). Any idea what's going on here?
Codesnippet:
const a = {
hi:1, bye:2, ciao: 3
}
const b = {hi, bye} = a
console.log(b)
Errormessage:
[nodemon] restarting due to changes...
[nodemon] starting `NODE_ENV=development babel-node server.js server.js`
/Users/user/Projects/fb/fb-flow-app/server/config/config.js:21
var b = (_a = a, hi = _a.hi, bye = _a.bye, _a);
^
ReferenceError: hi is not defined
at Object.<anonymous> (/Users/user/Projects/fb/fb-flow-app/server/config/config.js:12:8)
at Module._compile (internal/modules/cjs/loader.js:1123:30)
at Module._compile (/Users/user/Projects/fb/fb-flow-app/server/node_modules/pirates/lib/index.js:99:24)
at Module._extensions..js (internal/modules/cjs/loader.js:1143:10)
at Object.newLoader [as .js] (/Users/user/Projects/fb/fb-flow-app/server/node_modules/pirates/lib/index.js:104:7)
at Module.load (internal/modules/cjs/loader.js:972:32)
at Function.Module._load (internal/modules/cjs/loader.js:872:14)
at Module.require (internal/modules/cjs/loader.js:1012:19)
at require (internal/modules/cjs/helpers.js:72:18)
at Object.<anonymous> (/Users/user/Projects/fb/fb-flow-app/server/server.js:1:14)
[nodemon] app crashed - waiting for file changes before starting...
High-level project structure:
root
|-frontend
|-server
The frontend is a next.js project and has it's own .babelrc which seems to be working.
Steps taken so far
I've installed a couple of babel-dev-dependencies (in my server folder):
"devDependencies": {
"#babel/cli": "^7.10.1",
"#babel/core": "^7.10.2",
"#babel/node": "^7.10.1",
"#babel/preset-env": "^7.10.2",
...
}
and also tried (with no result)
#babel/plugin-transform-shorthand-properties
#babel/plugin-transform-spread
I've configured my nodemon.json:
{
"watch": ["../server"],
"exec": "NODE_ENV=development babel-node server.js",
"ext": "js"
}
I've set up a .babelrc
{
"presets": ["#babel/preset-env"]
}
And then I am running via:
"scripts": {
"start": "concurrently --prefix none \"cd server && NODE_ENV=development yarn nodemon server.js\" \"cd frontend && yarn dev\""
},
When you do the following:
const a = {
hi:1, bye:2, ciao: 3
}
const b = {hi, bye} = a
Babel sees an assignment to two variables, named hi and bye that don't yet exist. It seems that Babel is operating in strict mode where this is an error. You'll get the same in Node while in strict mode. Solve this by defining them explicitly:
const a = {
hi:1, bye:2, ciao: 3
}
let hi, bye;
const b = {hi, bye} = a
Destructuring does not make an object, despite it looking like an object initialization.
Note how, because of that, the value of b is not an object that looks like {hi:1, bye:2} but a reference to a, just like what would happen if you just do const b = a:
const b = a;
a.hi = 5;
console.log(b.hi); // 5
Other things you can do:
const {hi, bye} = a; to get two const variables named hi and bye (rather than var or let)
const {hi: b, bye: c} = a; to get two variables named b and
c ("renaming")
const {hi, bye} = a; const b = {hi, bye}; to make an object with just those two keys in variable b, but this will also create variables hi and bye.
I'm trying to implement SSR for a React application I started with creating a server directory that contains 3 files (bootstrap, index, renderer)
bootstrap.js contains babel configs to transpile to es5
index.js create an express application and express Router
renderer.js is responsible for rendering React application to string and send it as html to client.
bootstap.js =>
require('ignore-styles');
require('#babel/register')({
ignore: [
function (filePath) {
return !filePath.includes('node_modules');
}
],
presets: [
[
"#babel/preset-env",
{
"modules": false
}
],
'#babel/preset-react',
'#babel/flow'
],
plugins: [
[
"#babel/plugin-transform-runtime",
{
"regenerator": true
}
],
"#babel/plugin-proposal-object-rest-spread",
"#babel/plugin-syntax-dynamic-import",
"react-loadable/babel",
"#babel/plugin-proposal-class-properties",
"dynamic-import-node"
]
});
require('./index');
index.js =>
import dotenv from 'dotenv';
import cookieParser from 'cookie-parser';
dotenv.config();
const express = require('express');
const serverRenderer = require('./middleware/renderer');
const PORT = process.NODE_ENV === 'development' ? 3000 : 7160;
const path = require('path');
const app = express();
app.use(cookieParser());
const router = express.Router();
const routes = require('../src/router/appRoutes').default;
router.use(express.static(
path.resolve(__dirname, '..', 'build'),
{ maxAge: '30d' },
));
routes.map(path => app.get(path, serverRenderer));
app.use(router);
app.listen(PORT, (error) => {
if (error) {
return console.log('something bad happened', error);
}
console.log("listening on " + PORT + "...");
});
but when I run
NODE_ENV=production node server/bootstrap.js
this command to start server side application I get this error
import dotenv from 'dotenv';
^^^^^^
SyntaxError: Unexpected identifier
at Module._compile (internal/modules/cjs/loader.js:723:23)
at Module._compile (/Users/amirtahani/projects/uneed/node_modules/pirates/lib/index.js:99:24)
at Module._extensions..js (internal/modules/cjs/loader.js:789:10)
at Object.newLoader [as .js] (/Users/amirtahani/projects/uneed/node_modules/pirates/lib/index.js:104:7)
at Module.load (internal/modules/cjs/loader.js:653:32)
at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
at Function.Module._load (internal/modules/cjs/loader.js:585:3)
at Module.require (internal/modules/cjs/loader.js:692:17)
at require (internal/modules/cjs/helpers.js:25:18)
at Object.<anonymous> (/Users/amirtahani/projects/uneed/server/bootstrap.js:34:1)
and the weird thing is the same code is working on another project.
and here is my devDependencies
"devDependencies": {
"#babel/core": "7.6.4",
"#babel/plugin-proposal-class-properties": "7.5.5",
"#babel/plugin-proposal-object-rest-spread": "7.6.2",
"#babel/plugin-syntax-dynamic-import": "7.2.0",
"#babel/plugin-transform-classes": "7.5.5",
"#babel/plugin-transform-modules-commonjs": "7.6.0",
"#babel/plugin-transform-runtime": "7.6.2",
"#babel/preset-env": "7.6.3",
"#babel/preset-flow": "7.0.0",
"#babel/preset-react": "7.6.3",
"#babel/register": "7.6.2",
"babel-cli": "6.26.0",
"babel-plugin-dynamic-import-node": "2.3.0",
"babel-plugin-transform-es2015-modules-commonjs": "6.26.2",
"flow-bin": "0.102.0",
"ignore-styles": "5.0.1"
}
any ideas?
"import --from --" is ES15 syntax, however node.js uses commonJS module syntax. So you need to install and configure webpack. Babel just trans-piles the new generation javascript into the old javascript code. However webpack is going to bundle your application code into a single file and your server file will be executed through that bundle.js.
For server-side rendering you need 2 bundle.js. one for client and another one for server. HTML files without javascript have no functionality.
if we start from server, this is how we write our code into the index.js.
const renderToString=require("react-dom/server").renderToString //specifically created for server
const Home=require("./components/Home").default //home component
const React=require("react")
const express=require("express")
const app=express()
app.get("/",(req,res)=>{
const content =renderToString(<Home/>)
res.send(content)
})
This is how we render our code to the browser for "/" route. there are 2 flaws here. First one, we are sending file without javascript code. Any functionality in Home component will not work. For example, if you had button inside Home component with click event, that click event will not work. Because server is not shipping down any javascript code. Second flaw is we used jsx here:
const content =renderToString(<Home/>). so when node executes this file, it will not recognize this syntax and will give error.
to fix those 2 issues, we need webpack. webpack will transform index.js into a file which we specify the name and its location. In server-side, we usually name the file bundle.js inside public folder. So when we start the server with node or nodemon, we will execute public/bundle.js NOT the index.js file.
So we need to reorganize the code inside index.js and this time since webpack will transform the code, we can use "import" syntax.
import React from "react";
import { renderToString } from "react-dom/server";
import Home from "./components/Home"
import React from "react"
import express from "express";
const app=express()
app.use(express.static("public")) //This will make public folder publicly available so we can ship it down to the browser.
app.get("/",(req,res)=>{
const content=renderToString(<Home/>)
//I used template strings ``
const html= `
<html>
<head></head>
<body>
<div id="root">${content}</div>
<script src="bundle.js"> </script>
//since we are sending a file, express will look for bundle.js inside the public folder. So we do not need to write relative path or absolute path.
</body></html> `
res.send(html)
})
Now we need a file to configure webpack. We name it webpack.config.js in the root of the app.
const path=require("path")
module.exports={
//in server side we keep client and server logic inside src folder
entry:"./src/index.js", //relative path
mode:"development",
output:{filename:bundle.js,
path:path.resolve(__dirname,"build")},
//absolute path. that is why we use native node module path. also you do not need to create build folder. webpack will create automatically
module:{rules:[{test:/\.js$/,
loader:"babel-loader",
exclude:/node_modules/,
options:{presets:["#babel/preset-env","#babel/preset-react"]}}]}
}
lastly in package.json
"scripts": {
"dev:server": "nodemon --watch build --exec \"node build/bundle.js\"",
"dev:build-server": "webpack --config webpack.server.js --watch",
"dev:build-client": "webpack --config webpack.client.js --watch"
},
in dev:server we watch "build" folder for changes.(build folder is in the root of app.) then we execute "bundle.js" file inside the build directory.
so to give an answer to your question, this is the basic of server-side part of isomorphic javascript app.
I installed node LTS (v12.13.0) but got the same error when used import instead of require. It seems that es6 imports are still an experimental feature, even in the latest node version.
If you want to test this feature, you need to do these steps:
Add "type": "module" in your package.json
Run your server with this flag: --experimental-modules. e.g. NODE_ENV=production node --experimental-modules server/bootstrap.js
import and export syntax is still experimental in node js latest versions, but there is a work around to this issue.
try to add "type": "module" in your package.json file and change your .js bundle extension to .mjs in your webpack config and run your generated file with this command:
NODE_ENV=production node --experimental-modules server/bootstrap.mjs
also i recommend you to read this page.
First check if the dotenv package is installed or not. If not, you can install it in the following command -
npm i --save dotenv
In order to use dotenv, you don't need to import it and then configure it.
Instead use the following syntax -
require('dotenv').config()
I've distilled this issue down to a simple test. I'm using the node "config" module to define configuration values for my app. Pkg doesn't complain on build, but barfs at runtime with the following message. Am I missing something?
jim-macbookpro:~/development/node/pkgtest$ ./pkgtest-macos
pkg/prelude/bootstrap.js:1172
throw error;
^
Error: Cannot find module 'config'
1) If you want to compile the package/file into executable, please pay attention to compilation warnings and specify a literal in 'require' call. 2) If you don't want to compile the package/file into executable and want to 'require' it from filesystem (likely plugin), specify an absolute path in 'require' call using process.cwd() or process.execPath.
at Function.Module._resolveFilename (module.js:540:15)
at Function.Module._resolveFilename (pkg/prelude/bootstrap.js:1269:46)
at Function.Module._load (module.js:470:25)
at Module.require (module.js:583:17)
at Module.require (pkg/prelude/bootstrap.js:1153:31)
at require (internal/module.js:11:18)
at Object.<anonymous> (/snapshot/pkgtest/index.js:1:78)
at Module._compile (pkg/prelude/bootstrap.js:1243:22)
at Object.Module._extensions..js (module.js:650:10)
at Module.load (module.js:558:32)
index.js is simple:
const config = require('config');
console.log('yo:', config.message);
and I have a default.json in the local 'config' directory:
{
"message": "whodapunk?"
}
My package.json, for what it's worth:
{
"name": "pkgtest",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"config": "^1.30.0"
},
"bin": "index.js"
}
I had the same issue and it was because my config file was added to .gitignore -- as soon as I removed it from there it worked like a charm!
I just had the same issue. However not a really beautiful solution I managed to find a way to work around it.
When calling pkg I do not set e NODE_ENV. Then in my entry point I check if a NODE_ENV is set. If not I define the variables I need there.
let port = null;
let db = null;
let name = null;
if (process.env.NODE_ENV) {
const config = require('config');
port = config.get('port');
db = config.get('database');
name = config.get('name');
} else {
port = 3000;
db = 'mongodb://localhost:27017/production';
name = 'Server Production';
}
I tried linking directly to the config module but after that it started complaining that it could not find and files in my config folder. This worked for me as a work around.
Question:
I have a project in TypeScript that uses several APIs I don't have access to on my computer (they exist on the web). The code will compile fine locally since I have all the APIs in foo.d.ts files, and so the system knows they exist somewhere.
However, I want to unit test parts of the code with a NodeJS app. I can import the code into node just fine, but whenever I reach code that imports a module from a definition file, I get the following error:
Error: Cannot find module 'messages'
at Function.Module._resolveFilename (module.js:527:15)
at Function.Module._load (module.js:476:23)
at Module.require (module.js:568:17)
at require (internal/module.js:11:18)
at Object.<anonymous> (~/dev/repos/sample_typescript_fail/App.js:3:18)
at Module._compile (module.js:624:30)
at Object.Module._extensions..js (module.js:635:10)
at Module.load (module.js:545:32)
at tryModuleLoad (module.js:508:12)
at Function.Module._load (module.js:500:3)
...
This makes sense, since that code is just defined locally, and does not exist.
Can I manually register modules to NodeJS, like
Registry.register('messages', () => {...});
so that I can compile and test with polyfills?
Here's an example app
package.json
{
"name": "sample_typescript_declare_issue",
"version": "1.0.0",
"description": "",
"main": "index.ts",
"scripts": {
"start": "ts-node index.ts"
},
"author": "",
"license": "MIT"
}
index.ts
import {App} from "./App";
console.log("Starting program");
// How do I fake "import {MessageSender} from "messages";"
// here so that I can run this node app as a test?
let app: App = new App();
console.log("Ending program");
App.ts
import {MessageSender} from "messages";
export class App {
constructor() {
let messageSender: MessageSender = new MessageSender();
messageSender.sendMessage("foo!");
}
}
node_modules/#types/messages/index.d.ts
export = Messages;
export as namespace Messages;
declare module Messages {
class MessageSender {
constructor();
sendMessage(message: any): void;
}
}
Running Example App
Running with npm start gives the error message above.
Running tsc *.tsc compiles just fine.
Other things I've tried
Updating package.json to include a bin:
{
"name": "sample_typescript_declare_issue",
"version": "1.0.0",
"description": "",
"main": "index.ts",
"scripts": {
"start": "ts-node index.ts"
},
"author": "",
"license": "MIT",
"bin": {
"messages": "./polyfills/messages/index.ts"
}
}
As you mentioned, compiling works fine - this is just a question of availability of .d.ts files.
What you want to do is alter module import at runtime, in other words alter the behaviour of the nodejs require function since
import {MessageSender} from "messages";
will be transpiled in javascript (ES6) to something like
const messages_1 = require("messages");
...
messages_1.MessageSender
To modify that behaviour, the first thing that springs to mind is to use the deprecated - but still available - require.extensions object.
When running locally you must first inject something like
require.extensions['.js'] = (module, filename) => {
if (filename === 'messages') {
// then load mock module/polyfill using the passed module object
// see (https://nodejs.org/api/modules.html#modules_the_module_object)
}
};
The doc says there are better alternatives but fails to clearly mention any.
Another possibility is to look at projects like sandboxed-module which should help (I have not tested it)