Typescript/Node Unexpected token * - node.js

I'm trying to update my app node backend to typescript and I keep hitting this syntax error:
/Users/Shared/website/src/server.ts:1
(function (exports, require, module, __filename, __dirname) { import *
as express from 'express';
^
SyntaxError: Unexpected token *
I have my tsconfig/webpack/server, etc set up as follows:
server.ts
import * as express from 'express';
import * as path from 'path';
const app = express();
const port = process.env.PORT || 3000;
app.use(express.static(path.join(__dirname, 'dist')));
app.get('*', function(req, res, next){
res.sendFile(path.resolve(__dirname, '/public', 'index.html'));
});
app.listen(port, () => console.log(`Listening on port ${port}!`));
webpack.config.json:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const outputDirectory = 'dist';
module.exports = {
entry: "./src/index.tsx",
output: {
filename: "bundle.js",
path: path.join(__dirname, outputDirectory)
},
mode: 'development',
// Enable sourcemaps for debugging webpack's output.
devtool: "source-map",
resolve: {
// Add '.ts' and '.tsx' as resolvable extensions.
extensions: [".ts", ".tsx", ".js", ".json"]
},
module: {
rules: [
// All files with a '.ts' or '.tsx' extension will be handled by 'awesome-typescript-loader'.
{ test: /\.tsx?$/, loader: "ts-loader" },
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ enforce: "pre", test: /\.js$/, loader: "source-map-loader" },
{
test: /\.scss$/,
use: [
"style-loader", // creates style nodes from JS strings
"css-loader", // translates CSS into CommonJS
"sass-loader" // compiles Sass to CSS, using Node Sass by default
]
}
]
},
// When importing a module whose path matches one of the following, just
// assume a corresponding global variable exists and use that instead.
// This is important because it allows us to avoid bundling all of our
// dependencies, which allows browsers to cache those libraries between builds.
externals: {
},
plugins: [
new CleanWebpackPlugin([outputDirectory]),
new HtmlWebpackPlugin({
template: './public/index.html',
favicon: './public/favicon.gif'
}),
new CopyWebpackPlugin([
{ from: 'public' }
])
]
};
tsconfig.json:
{
"compilerOptions": {
"outDir": "./dist/",
"sourceMap": true,
"noImplicitAny": false,
"module": "commonjs",
"target": "es6",
"jsx": "react"
},
"include": [
"./src/**/*"
],
}
The build process succeeds, but I hit the syntaxError on run. I have a react front end also set up using typescript / tsx and it works just fine. I seem to just be running into issues with the server.ts / node files. I'm very new to trying to get this all set up, but I wanted practice making a site with numerous technologies (react/node/typescript/sass/webpack/etc). So far I have everything except the typescript/node relationship.

I had the same problem, after I realised that the tsconfig wasn't applied.
If
"module": "commonjs"
was in effect, you wouldn't have this error.

I faced the same problem before. I solve it by changing the import 'call':
From:
import * as express from 'express';
To:
const express = require('express');

As others have stated, the problem is that your tsconfig.json is not applied to server.ts. You have left out important details of your setup which is why others cannot duplicate this problem.
I have a good guess at what the issue is and having struggled with this identical problem myself, I will explain my guess here in the hope of helping some other poor soul being tormented by this issue.
The basic problem is that your server code is in a different tree than your react code. This is why the tsconfig.json is not being applied to it since (I believe) it is outside the "./src/" path specified. (Perhaps "./website/src/").
You haven't shown us the package.json file but very likely the server entry is something like "server": "ts-node ./website/src/server.ts"
To verify that the tsconfig.json application is the issue try this from the command line...
$ ts-node -O '{\"module\":\"commonjs\"}' ./website/src/server.ts
Chances are, things will start working. Now the solution is probably as simple as adding another path your tsconfig.json includes.

So I came across this post on github where basically there are two sort of working methods presented since you’re using a bundling tool targeted to es6 add
"allowSyntheticDefaultImports": true to ”compilerOptions”
Or change
import express from "express";
to
import express = require('express');

This might be happening if your tsconfig.json isn't at the root of your project. Configure webpack to point to your target config file (which you can alter with variables to point to dev and prod configurations).
https://github.com/TypeStrong/ts-loader
If set, will parse the TypeScript configuration file with given absolute path as base path. Per default the directory of the configuration file is used as base path. Relative paths in the configuration file are resolved with respect to the base path when parsed. Option context allows to set option configFile to a path other than the project root (e.g. a NPM package), while the base path for ts-loader can remain the project root.
Try modifying your webpack.config.js file to have this:
module.exports = {
...
module: {
rules: [
{
options: {
configFile: path.join(__dirname, "tsconfig.json")
}
}
]
}
};

Related

Webpack when using readdirSync for require a library

I have a legacy code for my express app that read all routes files in specific dir and require them in a loop. Notice this code cant be changed:
app.js
const normalizedRoutes = fs.readdirSync(__dirname + '/src/routes/')
.map(routeFile => `/src/routes/${routeFile}`);
normalizedRoutes.forEach((normalizedRouteDir: string) => {
require(normalizedRouteDir)(app);
})
Now, I want to combine a Server Side Rendered application with the code above, using some JSX in routes files.
My problem is because the routes files are loaded on run time webpack not recognize them when creating the bundle.js file.
Therefore there are not routes files in the /src/routes/${routeFile} and when I run the bundle.js file I get an error message of:
Error: ENOENT: no such file or directory, scandir '/Users/******/build/src/routes/'
(the stars are for hiding full path)
webpack configs:
webpack.base.js
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
module.exports = {
plugins: [new MiniCssExtractPlugin()],
module: { //remain
rules: [
{
test: /\.(ts|js)x?$/,
loader:'babel-loader',
exclude: /node_modules/,
options:{
presets:[
'#babel/react',
['#babel/env',{targets:{browsers:['last 2 versions']}}]
]
}
},
{
test: /\.css$/i,
use: [MiniCssExtractPlugin.loader, "css-loader"],
},
],
}
};
webpack.server.js
const path = require('path')
const {merge} = require('webpack-merge')
const baseConfig = require('./webpack.base.js');
const webpackNodeexternals = require('webpack-node-externals');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const config = {
mode: "development",
entry: {
main:"./app.ts",
},
resolve: {
extensions: [".js", ".jsx", ".json", ".ts"],
},
node: {
__dirname: true
},
output: {
libraryTarget: "commonjs",
path: path.join(__dirname, "build"),
filename: "bundle.js",
},
target: "node",
//Avoid put node modules of server when sending to browser
externals: [webpackNodeexternals()]
}
module.exports = merge(baseConfig,config)
scripts from package.json:
"dev:server": "nodemon --watch build --exec \"node build/bundle.js\" ",
"dev:build-server": "webpack --config webpack.server.js --watch",
When I copy the route files (js files) to the build directory it works of course but that means I don't run webpack on these files and therefore I can't include JSX\es6 features inside these files.
So my question is:
Is there any possible way to make these requires identify by webpack/babel to add them to bundle.js and avoid the need for seperate files (bundle.js and routes files)
If we cant do it, how can I run webpack on a folder seperatly from the bundle.js output and create a route folder in the correct path but after processed by babel?
Thanks!
Instead of using a Webpack you can try using a programmatic interface of babel, and transpile the files before requiring them.
Here is the link https://babeljs.io/docs/en/babel-core

Node/Webpack: Load package.json with ES6

I want to load my package.json in an ES6 environment and access it like pkg.name.
My solution so far is making a simple module for reading the file with fs, parsing it and import this module in every place I need to access it.
The problem is, I want to bundle my script with webpack and the path to the package.json is resolved to my current path from my pc I bundle everything. Like: D:/dev/app-name/package.json
This is wrong, I need a way to run the bundled script afterwards on e.g. a separate pc, or linux and still find the package.json. Is there a way to tell webpack to not resolve this path, or is there another (simpler) way to use the "root" path in my script?
My bundled app is an express server and I'm using webpack 5.
src/api/package-json.js:
import path from 'path'
import { fileURLToPath } from 'url'
import fs from 'fs-extra'
// Path CONST
// we need to change up how __dirname is used for ES6 purposes
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const PROJECT_ROOT = path.join(__dirname, '..', '..')
const PKG_FILE = path.join(PROJECT_ROOT, 'package.json')
// Package.json
const pkg = JSON.parse(fs.readFileSync(PKG_FILE)) // import pkg from '~root/package.json'
export default pkg
src/api/app.js:
import pkg from './package-json.js'
console.log(pkg.name)
webpack.config.js:
import path from 'path'
import { fileURLToPath } from 'url'
// import nodeExternals from 'webpack-node-externals'
// we need to change up how __dirname is used for ES6 purposes
const __dirname = path.dirname(fileURLToPath(import.meta.url))
const { NODE_ENV = 'production' } = process.env
export default {
entry: './src/api/app.js',
mode: NODE_ENV,
target: 'node',
node: {
global: false,
__filename: false,
__dirname: false
},
output: {
path: path.resolve(__dirname, 'dist', 'server'),
filename: 'app.cjs'
},
resolve: {
extensions: ['.js', '.jsx', '.ts', '.tsx']
},
externals: {
'node-pty': 'commonjs2 node-pty'
}
}
I found a workaround with process.cwd(), but I don't think this is a good solution for my problem. The problem is, process.cwd() can be changed in runtime as far as I know. :(
src/api/package-json.js:
import path from 'path'
import fs from 'fs-extra'
// Path CONST
const PROJECT_ROOT = process.cwd()
const PKG_FILE = path.join(PROJECT_ROOT, 'package.json')
// Package.json
const pkg = JSON.parse(fs.readFileSync(PKG_FILE)) // import pkg from '~root/package.json'
export default pkg

add material-components-web.css via webpack

I added the mterial-components-web.css to the header of my index.html file.
<script src="node_modules/material-components-web/dist/material-components-web.js"></script>
<script src="dist/bundle.js"></script>
the css components work great. Now I added a few javscript components via webpack. Now I thouhgt I could add all vai webpack into my bundle.js.
import 'material-components-web/dist/material-components-web.js';
no error, but no styles loaded! wheres the problem?
regards
my webpack config.
const path = require('path');
const ExtractTextPlugin = require("extract-text-webpack-plugin");
module.exports = {
entry: './src/app.js',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js'
},
module: {
rules: [
{
test: /\.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: ['css-loader', 'sass-loader']
})
}
]
},
plugins: [
new ExtractTextPlugin('style.css')
],
devServer: {
contentBase: "./build"
}
};
Its difficult to pin down the exact cause without looking at webpack config.
Nevertheless, CSS needs two loaders as suggested in webpack docs. I can only guess that the loaders are not in place.
One can use inline import too as explained here
Though not near to what you are trying feel free to scan through this simple code that have. It basically has bootstrap css bundled via webpack. Note, however though, i have used require() and not import. Shouldnt be difficult to switch with proper js precompiler added in webpack config.

Cannot find entry module in webpack using nodejs API

I am trying to run webpack from within nodejs. My directory structure looks like this:
build
|- dev.js
dist
|- bundle.js
src
|- layout
|- App.js
|- server
|- app.js
dev.js:
const webpack = require('webpack');
const path = require('path');
// returns a Compiler instance
const compiler = webpack(
{
context: path.resolve(__dirname, '../src'),
entry: [
'./server/app.js'
],
output: {
path: path.join(__dirname, '../dist'),
filename: 'bundle.js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader?presets[]=es2015&presets[]=react'
}
]
}
}
);
compiler.run(function(err, stats) {
if(err) {
console.log('Err');
}
});
app.js:
import express from 'express';
import React from 'react';
import { renderToString } from 'react-dom/server';
import App from '../layout/App';
const app = express();
app.get('*', (req, res) => {
res.send(renderToString(<App />));
});
app.listen(3000, () => {
});
If I now run node build/dev.js it generates my bundle.js, but it does not find my entry module.
(function webpackMissingModule() { throw new Error("Cannot find module \"./server/app.js\""); }());
Even though I think this is how the entry point should be defined, I have tried many combinations, even the absolute path. But always the same result, it cannot find the entry module. What am I missing here?
It looks like something is going wrong with bundling the assets - since webpack looks in your node_modules to find its assets it, would be best if you could post your package.json alongside the other files.
You're using webpack programatically instead of the default webpack command, which normally gives a lot of debug output (along with information about the build-steps, errors, etc.) - I would suggest using that to debug it, and then switch to the programmatical approach when you know that everything is working.
It looks like you want to do server-side rendering with react. Some special configuration is needed for your webpack configuration then. This is already handled here: http://jlongster.com/Backend-Apps-with-Webpack--Part-I
Without having the package.json it is really hard to debug exactly what goes wrong here.
Assuming your package.json is correct, here's a dev.js file that would work with the above code:
const webpack = require('webpack');
const path = require('path');
const fs = require('fs');
var nodeModules = {};
fs.readdirSync('node_modules')
.filter(function(x) {
return ['.bin'].indexOf(x) === -1;
})
.forEach(function(mod) {
nodeModules[mod] = 'commonjs ' + mod;
});
// returns a Compiler instance
const compiler = webpack(
{
context: path.resolve(__dirname, "../src"),
target: 'node',
entry: [
'./server/app.js'
],
output: {
path: path.join(__dirname, '../dist'),
filename: 'bundle.js'
},
module: {
loaders: [
{
test: /\.js$/,
exclude: /node_modules/,
loader: 'babel-loader?presets[]=es2015&presets[]=react'
}
]
},
externals: nodeModules
}
);
compiler.run(function(err, stats) {
console.log(err, stats);
});

webpack-dev-middleware and Express - can't get them to collaborate

I am trying to set up my first project using Webpack and Express but somehow I am doing something wrong.
This is what I did:
1. CREATED SAMPLE PROJECT
Created a sample project using express-generator. My folder structure is something like:
express-project
-app.js
-webpack.config.js
-public
-javascripts
-modules
-build
2. SET UP HANDLEBARS
Set up handlebars as view/template engine and created a couple of routes
3. WEBPACK CODE
Created the Webpack specific code/configuration as follows
webpack.config.js
var webpack = require('webpack');
var path = require('path');
var webpackHotMiddleware = 'webpack-hot-middleware/client?path=/__webpack_hmr&timeout=2000&overlay=false';
module.exports = {
resolve: {
alias: {
handlebars: path.resolve('public/vendor/handlebars-v4.0.5.js'),
bootstrap: path.resolve('public/vendor/bootstrap/js/bootstrap.js'),
pubsub: path.resolve('public/vendor/ba-tiny-pubsub.js')
}
},
context: path.resolve('public/javascripts'),
entry: {
cart: ['./modules/cart', webpackHotMiddleware],
index: ['./modules/products.js', webpackHotMiddleware],
vendor: ['bootstrap', 'pubsub', webpackHotMiddleware]
},
output: {
path: path.resolve('public/javascripts/build'),
publicPath: 'javascripts/build/',
filename: '[name].js',
chunkFilename: "[id].js"
},
module: {
loaders: [
// some loaders here
]
},
plugins: [
new webpack.optimize.OccurenceOrderPlugin(),
new webpack.HotModuleReplacementPlugin(),
new webpack.NoErrorsPlugin()
]
}
app.js
// some code before
var app = express();
(function() {
// Step 1: Create & configure a webpack compiler
var webpack = require('webpack');
var webpackConfig = require(process.env.WEBPACK_CONFIG ? process.env.WEBPACK_CONFIG : './webpack.config');
var compiler = webpack(webpackConfig);
// Step 2: Attach the dev middleware to the compiler & the server
app.use(require("webpack-dev-middleware")(compiler, {
noInfo: false,
publicPath: webpackConfig.output.publicPath,
stats: {
colors: true
}
}));
// Step 3: Attach the hot middleware to the compiler & the server
app.use(require("webpack-hot-middleware")(compiler, {
log: console.log,
path: '/__webpack_hmr',
heartbeat: 10 * 1000
}));
})();
// some code after
4. JS CODE ON TEMPLATE
Then on the handlebars page I require the bundled javascripts
<script src="javascripts/build/common.js"></script>
<script src="javascripts/build/vendor.js"></script>
<script src="javascripts/build/cart.js"></script>
5. NPM START
Finally if I start the server using the standard npm start I see in the shell that webpack bundles everything with no errors but if I go to localhost:3000/ it does not find any of the assets created by Webpack. Instead if I run webpack to create the various bundles as if I were on production, everything is created correctly and it works as expected.
Hope someone can figure out what I am doing wrong.
Thanks
I managed to figure out what was causing the problem, by adding a slash in these 2 lines everything started to work properly:
context: path.resolve('public/javascripts/'),
path: path.resolve('public/javascripts/build/'),

Resources