Electron-Typescript: Bundling everything - javascript

I'm trying to create a web app using electron written in Typescript. I'm having problems when building my application. Specifically, I am not sure on how to combine: tsc (To convert my .ts file to .js) and then electron dist/main.js. Potentially, I want to run npm start which first compiles my .ts file and then run electron. Can anyone comment on what would be the best approach to achieve this?

Use ts-loader with webpack to bundle .ts files with config like below,
const path = require("path")
module.exports = {
entry: './src/index.ts',
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/
}
]
},
resolve: {
extensions: [ '.tsx', '.ts', '.js' ]
},
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist')
}
};
and then in your npm script include these,
{
"build-watch": "webpack -w",
"electron": "electon dist/main.js"
}
then start both using npm-run-all (or any other tool like concurrently),
npm-run-all start build-watch electron

I would suggest using https://webpack.electron.build/. It has instructions for adding typescript support here https://webpack.electron.build/add-ons#typescript

Related

Webpack doesn't run clean when watch is set to true

This is my webpack.config.js file:
const path = require('path');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const config = {
entry: {
bundle: './javascript/index.js'
},
output: {
path: path.resolve(__dirname, 'build'),
filename: '[name].[chunkhash].js'
},
module: {
rules: [
{
use: 'babel-loader',
test: /\.js$/,
exclude: /node_modules/
},
{
test: /\.css$/,
use: ExtractTextPlugin.extract({
fallback: "style-loader",
use: "css-loader"
})
},
{
test: /\.(jpe?g|png|gif|svg)$/,
use: [
{
loader: 'url-loader',
options: {
limit: 40000
}
},
'image-webpack-loader'
]
}
]
},
plugins: [
new ExtractTextPlugin('style.css'),
new HtmlWebpackPlugin({
template: 'src/index.html'
})
],
watch: true
};
module.exports = config;
As you can tell from the last line I'm setting the watch option to true. In addition, I'm using chunkhash to generates a new javascript file when I make a change to any of my javascript files. However, it is not running my rinraf clean command when the watch option is set to 'true'.
Here is a portion of my package.json file that:
{
"name": "budgety",
"version": "1.0.0",
"description": "Budget app",
"main": "app.js",
"scripts": {
"clean": "rimraf build",
"build": "npm run clean && webpack"
},
.
.
.
Why is this happening?
My goal is to:
Have my compiled javascript be updated after I update any of my javascript files, so I don't need to run 'npm run build' every single time I make a change to my js files.
Clean the old javascript 'hashed' file which used be taken care of by 'rimraf' but for some reason it isn't cleaning the new hashed javascript files in watch mode.
The watch mode works in a way that it only recompiles the files that were changed. That's why, normally, during the watch mode the hash prefixes are not enabled (because the files are changed nearly every minute which makes it more complicated to track the changed hashes etc). In other words one should have a dev and prod environments that will behave slightly differently.
E.g. you need to pass an argument, see here how and then use them in your config file:
filename: env.withHashPrefixes ? '[name].[chunkhash].js' : '[name].js'
Now you will not need to clean anything because the filenames are always the same
Original answer
It does and it will not run your rimraf command because the watch happens inside of the webpack ind it has no idea what you did run outside of it.
Use clean-webpack-plugin which is as easy as
plugins: [
new CleanWebpackPlugin('build')
]
I've experienced the same problem that my assets in /assets/ folder were cleaned and not rebuilt when enabling output.clean.
I've worked around this by ignoring /assets/ from cleaning in webpack.config.js. However, it's not the perfect solution as obsolete assets would remain in the folder.
output: {
clean: {
keep: /assets\//,
},
},

"webpack" vs "webpack --watch" creates different output

Im using this set up as the base of my project: https://www.typescriptlang.org/docs/handbook/react-&-webpack.html
When I run webpack, it compiles a bundle that works in the browser.
When I run webpack --watch, it re-compiles on file change, but causes this error in the browser:
Uncaught ReferenceError: exports is not defined
I looked at the output of both, and it looks like webpack --watch does not include the webpack bootstrap code or my modules - only the entry file transpiled.
webpack
Includes all of my modules in a single file, along with using webpacks own module require.
E.g: var io = __webpack_require__(20);
webpack --watch
Only includes my entry module - no other modules, no __webpack_require__.
E.g. var io = require("socket.io-client");
Versions:
- webpack: 3.7.1
- tsc: 1.8.10
module.exports = {
entry: "./src/index.tsx",
output: {
filename: "bundle.js",
path: __dirname + "/dist"
},
// 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: "awesome-typescript-loader" },
// All output '.js' files will have any sourcemaps re-processed by 'source-map-loader'.
{ enforce: "pre", test: /\.js$/, loader: "source-map-loader" }
]
},
// 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: {
"react": "React",
"react-dom": "ReactDOM"
}
The fix is to remove outDir from tsconfig.json:
{
"compilerOptions": {
"outDir": "./dist/"
}
}
It was the tsconfig.json file having a conflicting output directory. Files are only written by typescript when using webpack --watch

Webpack - [HMR] Hot Module Replacement is disabled

I've looked around, but can't get any of the answers I've seen on stackoverflow to work.
I cannot use the command line for webpack or the webpack dev-server; I am restricted to using the Node API.
Below is how I am using webpack.
webpack.config.js
module.exports = {
entry: [
'webpack-dev-server/client?http://localhost:3000',
// i've also tried webpack/hot/dev-server here
'webpack/hot/only-dev-server',
path.join(__dirname, 'src', 'js', 'app.jsx')
],
output: {
path: path.join(__dirname, 'dist', 'js'),
filename: 'script.js',
publicPath: '/dist/'
},
module: {
loaders: [{
test: /\.(js|jsx)$/,
loaders: ['react-hot', 'babel']
}]
},
plugins: []
};
contained in a gulp task "start"
gulp.task('start', function (callback) {
var config = Object.create(require('webpack.config.js'));
config.plugins.push(new webpack.HotModuleReplacementPlugin());
var devServer = new webpackDevServer(webpack(config), {
stats: { colors: true },
contentBase: path.resolve(__dirname, 'dist'),
progress: true,
inline: true,
hot: true
});
});
What I expect
When I run gulp start, I expect the webpack dev server to spin up, allowing me to hit localhost:3000/. This should load an index.html from my project's /dist/ folder. So far so good. I expect that when I make a change to a file (e.g., app.jsx), that the change would be present.
What is actually happening
I am getting the error "[HMR] Hot Module Replacement is disabled", with no further explanation.
Any help would be appreciated. I have been trying to get hot reloading working for a full day.
in your webpack.config.js on the plugins section try this,
plugins: [new webpack.HotModuleReplacementPlugin()]
I know you are pushing the plugin in your gulp task but you have to use --hot --inline on cli or on your npm script
Try to run webpack as
webpack-dev-server --hot --inline in packge.json,
somehow official docs is wrong now.

Making a library importable using webpack and babel

I am trying to publish a package on npm (this one) that I am developing using webpack and babel. My code is written in ES6. I have a file in my sources, index.js, that (for the moment) exports one of my library's core components, it simply goes like this:
import TheGamesDb from './scrapers/thegamesdb';
export { TheGamesDb };
I am using webpack and babel to create a dist index.js that is my package's main file. My webpack.config.js goes like this:
const webpack = require('webpack');
const nodeExternals = require('webpack-node-externals');
module.exports = {
entry: {
index: ['babel-polyfill', './src/index.js'],
development: ['babel-polyfill', './src/development.js']
},
output: {
path: '.',
filename: '[name].js',
library: 'rom-scraper',
libraryTarget: 'umd',
umdNamedDefine: true
},
devtool: 'source-map',
module: {
loaders: [
{ test: /\.js$/, loader: 'babel-loader', exclude: /node_modules/ }
]
},
target: 'node',
externals: [nodeExternals()]
};
Now when I load my package in another project and try to import my export TheGamesDb simply like this
import { TheGamesDb } from 'rom-scraper';
I get the error
Uncaught TypeError: Path must be a string. Received undefined
It is to be noted that I am importing my library in electron.
Update: Electron seems to be the main problem here and it is not even my library but a dependency that throws this error (only in Electron)
The problem wasn't any of the things in my question but node-expat not working in electron. I switched to an alternative library and it's all right now.

How to load library source maps using webpack?

I'm building two projects with webpack; one is a library for the other.
Is it possible to consume the sourcemaps from my library project when building my wrapper project? I would like the ability to debug my library code from my wrapper UI.
My build works correctly in that the library is built in. The only issue is sourcemaps. The JavaScript I see in the browser debugger is uglified, because sourcemaps are unavailable.
Snippet of my project structure:
+-- my-ui/
+-- dist/
+-- my-ui.js
+-- my-ui.js.map
+-- node_modules/
+-- my-lib/
+-- dist/
+-- bundle.js
+-- bundle.js.map
Snippet from webpack.config.js:
module.exports = {
entry: './src/js/main.jsx',
output: {
path: path.join(__dirname, 'dist'),
filename: 'my-ui.js',
library: 'my-ui',
libraryTarget: 'umd'
},
devtool: 'source-map',
module: {
loaders: [
{test: /\.jsx?$/, loader: 'babel', include: path.join(__dirname, 'src')}
]
},
plugins: [
new Clean('dist'),
new HtmlWebpackPlugin({
template: 'src/index.html',
inject: true
})
]
};
I finally figured out my issue...
Thanks to #BinaryMuse for the tip on source-map-loader. This indeed was the right way to go, though it wasn't working for me initially.
What I eventually realized is that I need to enable the source-map-loader for webpack in both "my-lib" and "my-ui". Without source-map-loader in "my-lib" webpack config, the source-map-loader inside "my-ui" errors (with a warning message sadly) because it cannot locate source maps for transitive dependencies of "my-lib". Apparently the source maps are so good that source-map-loader is able to peek at all aspects of the dependency tree.
Also of note, I ran into an issue using source-map-loader in conjunction with react-hot-loader. See, react-hot-loader does not include source maps. When source-map-loader tries to find them (because it's just scanning everything), it cannot and aborts everything.
Ultimately, I'd like source-map-loader to be more fault tolerant, but when set up correctly, it does work!
devtool: 'source-map',
module: {
preLoaders: [
{test: /\.jsx?$/, loader: 'eslint', exclude: /node_modules/},
{test: /\.jsx?$/, loader: 'source-map', exclude: /react-hot-loader/}
],
loaders: [
{test: /\.jsx?$/, loader: 'raect-hot!babel', exclude: /node_modules/}
]
}
My answer is similar to #Jeff Fairley's and I had the same directory structure, with the only difference being that I was using module: { rules: [] } instead of his module: { preLoaders: [..], loaders: [...]}. This is what I had to add to my webpack.config.js file:
mode: 'development',
devtool: 'eval-source-map',
module: {
rules: [
{
test: /\.js$/,
enforce: "pre",
use: ["source-map-loader"],
}
]
},
Then I ran
npm i -D source-map-loader
and I saw the TypeScript source code of the dependency I was using when clicking through tracebacks in Chrome's devtools. See the Webpack docs for source-map-loader.
I am using create-react-app and this is how I Fixed it (without running eject cmd)
Note : If your app is already overriding webpack config using react-app-rewired you can ignore first three steps.
npm i react-app-rewired -D - This will help you to override webpack
configuration.
package.json - change your scripts, replace react-scripts with react-app-rewired
"scripts": {
"start": "react-app-rewired start",
"build": "react-app-rewired build",
"test": "react-app-rewired test",
"eject": "react-app-rewired eject"
}
config-overrides.js - create this file in the parent level of the app.
npm i source-map-loader -D - To load source maps (assuming that your lib's dist has source map file). It doesn't matter which build tool(ex: Rollup, webpack or parcel) you use to generate sourcemap.
Copy below code in config-overrides.js
module.exports = {
webpack: (config, env) => {
// Load source maps in dev mode
if (env === 'development') {
config.module.rules.push({
test: /\.(js|mjs|jsx|ts|tsx)$/,
use: ['source-map-loader'],
enforce: 'pre',
});
// For `babel-loader` make sure that sourceMap is true.
config.module.rules = config.module.rules.map(rule => {
// `create-react-app` uses `babel-loader` in oneOf
if (rule.oneOf) {
rule.oneOf.map(oneOfRule => {
if (
oneOfRule.loader &&
oneOfRule.loader.indexOf('babel-loader') !== -1
) {
if (oneOfRule.hasOwnProperty('options')) {
if (oneOfRule.options.hasOwnProperty('sourceMaps')) {
// eslint-disable-next-line no-param-reassign
oneOfRule.options.sourceMaps = true;
}
}
}
});
}
return rule;
});
}
return config;
},
};
Restart your app (if it's already running). source files get loaded in different locations, based on path in map file. Check all folders patiently :)
Note :
1. Your source maps get loaded in one of the folder(ex : localhost:3000 or webpack:/// ) based on path it reads from xxx.js.map file.
2. If you are using rollup for your libs, please make sure you give proper path in the configuration file (output.sourcemapPathTransform ), This will help to load sourcemaps in the proper location.
You should be able to use any of the eval source map options that Webpack provides.
Really that just amounts to setting the right devtool option in your webpack.config.js for the my-lib project.
devtool: 'eval',
eval and eval-source-map should both work.
See the Webpack documentation for the various options.

Categories