Compiling a typescript project with webpack - javascript

I have a question for you - how is it possible to implement multi-file compilation while preserving the tree of folders and documents, while not writing each file into entry in this way
entry: {
index:'./src/index.ts',
'bot/main':'./src/bot/main.ts'
}
But at the same time, the files had their names and their position, as before compilation in js, only instead of the src folder, they were in the dist folder?
My current config webpack.config.js
const path = require('path')
const nodeExternals = require('webpack-node-externals')
const TsconfigPathsPlugin = require('tsconfig-paths-webpack-plugin')
module.exports = {
context: __dirname,
entry: {
index:'./src/index.ts',
'bot/main':'./src/bot/main.ts'
},
externals: [nodeExternals()],
module: {
rules: [
{
exclude: /node_modules/,
test: /.ts$/,
use: {
loader: 'ts-loader'
}
}
]
},
node: {
__dirname: false
},
resolve: {
extensions: ['.ts', '.js'],
plugins: [
new TsconfigPathsPlugin({
baseUrl: './src'
})
]
},
output: {
filename: '[name]js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/dist/'
},
target: 'node'
}
And when building in production mode, all this was compiled into one file, taking into account all URLs, imports, etc.
Is it even possible?

Webpack itself won't do that for you. You will need to write litter helper function to achieve this. The basic idea is to crawl the directory, find all the files and then provide them to Webpack:
const path = require('path');
const glob = require('glob');
const extension = 'ts';
// Recursively find all the `.ts` files inside src folder.
const matchedFiles = glob.sync(`./src/**/*.${extension}`, {
nodir: true
});
const entry = {};
matchedFiles.forEach((file) => {
const SRC_FOLDER = path.join(__dirname, 'src');
const ABS_PATH = path.join(__dirname, file);
// Generates relative file paths like `src/test/file.ts`
const relativeFile = path.relative(SRC_FOLDER, ABS_PATH);
// fileKey is relative filename without extension.
// E.g. `src/test/file.ts` becomes `src/test/file`
const fileKey = path.join(path.dirname(relativeFile), path.basename(relativeFile, extension));
entry[fileKey] = relativeFile;
});
module.exports = {
context: __dirname,
// Use the entry object generated above.
entry,
// ... rest of the configuration
};

Related

Webpack bundle behaviour different from 5.21.0 and 5.22.0

I am doing some upgrades to node a package which uses webpack. The package used to use webpack 5.9 for generating a small bundle, then using eval() was extracting some js code.
This is the webpack conf:
function getBaseWebpackConfig() {
return {
context: path.resolve(__dirname, '../'),
mode: 'development',
entry: "./test/input/icon.js",
devtool: false,
output: {
path: outputDir,
filename: bundleFileName,
publicPath: '',
library: {
type: 'commonjs2',
}
},
module: {
rules: [
{
test: /\.svg/,
exclude: /node_modules/,
loader: svg-loader,
options: {}
}
]
}
}
}
Now, moving to 5.73.0, this behaviour has changed; tests stopped running. After doing some debug, I have found the following.
With webpack < 5.21.2 the bundle starts as:
module.exports =
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
With webpack > 5.22.0 the bundle starts as:
/******/ (() => { // webpackBootstrap
/******/ var __webpack_modules__ = ({
Essentially, it does not have a top module.exports anymore and this breaks the rest of the code.
I could not find any reason this. The changelog does not give me any clue. Might it be a bug?
I'm not a webpack expert. But, comparing yours with my webpack configs I created recently (using the latest webpack for a PWA app). My settings are inside a module.exports. Maybe that's why module.exports is not in your bundle. e.g.
module.exports = {
context: path.resolve(__dirname, '../'),
mode: 'development',
entry: "./test/input/icon.js",
devtool: false,
output: {
path: outputDir,
filename: bundleFileName,
publicPath: '',
library: {
type: 'commonjs2',
}
},
module: {
rules: [
{
test: /\.svg/,
exclude: /node_modules/,
loader: svg-loader,
options: {}
}
]
}
}
}
Plus I've got three webpack config files common,dev and prod and use merge to combine them.
e.g. my webpack.dev.js
const { merge } = require('webpack-merge');
const common = require('./webpack.common.js');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const ForkTsCheckerNotifierWebpackPlugin = require('fork-ts-checker-notifier-webpack-plugin');
const path = require('path');
module.exports = merge(common, {
mode: 'development',
devtool: 'inline-source-map',
output: {
filename: "[name].bundle.js",
},
module: {
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css"
}),
new ForkTsCheckerNotifierWebpackPlugin(),
]
});

after upgrade to Webpack 5 not able to access the menifest in copy-webpack-plugin

My config was working fine in webpack version 4.6.0 and webpack-assets-manifest version 3.1.1
since I upgraded to webpack 5 and webpack-assets-manifest to 5. I'm not getting value in my manifestObject it's just empty object
I suspect this is happening because transform function running before manifest is created
looked into the new documentation of webpack-assets-manifest but could not get it working
my goal is to access manifest value in transform function, but it looks like transform function is running before manifest is generated
var CopyWebpackPlugin = require('copy-webpack-plugin');
var SaveHashes = require('webpack-assets-manifest');
const manifest = new SaveHashes({
entrypoints: true,
entrypointsKey: 'entryPoints'
});
module.exports = {
entry: {
main: ['./src/apps/main'],
games: ['./src/apps/games'],
},
output: {
path: path.join(__dirname, 'dist'),
publicPath: assetsUrl,
filename: 'assets/javascript/[name].[contenthash].js',
chunkFilename: 'assets/javascript/[name].[contenthash].js'
},
.
.
.
.
.
plugins: [
new CleanWebpackPlugin(),
manifest,
new CopyWebpackPlugin([
{
from: './views/**/*',
to: path.join(__dirname, 'dist'),
transform(content, path) {
// I want to access manifest here
// so that I can inject the final script(javascript bundle with content hash)
// in my view template
const manifestObject = JSON.parse(manifest);
}
}
])
]
};
you need to export it like this
const ManifestPlugin = require("webpack-manifest-plugin").WebpackManifestPlugin;
.....
new ManifestPlugin({
fileName: "asset-manifest.json",
publicPath: paths.publicUrlOrPath,
generate: (seed, files, entrypoints) => {
const manifestFiles = files.reduce((manifest, file) => {
manifest[ file.name ] = file.path;
return manifest;
}, seed);
const entrypointFiles = entrypoints.main.filter(
(fileName) => !fileName.endsWith(".map")
);
return {
files: manifestFiles,
entrypoints: entrypointFiles,
};
},
}),
and it will work WebpackManifestPlugin is what you need

Compiling with webpack into single file

So I have the following webpack.config.js file:
const path = require('path');
const JS_DIR = path.resolve(__dirname, '/js');
const BUILD_DIR = path.resolve(__dirname, 'js');
const entry = {
main: JS_DIR + '/main/main.js',
all: JS_DIR + '/all.js',
};
const output = {
path: BUILD_DIR,
filename: 'js/main/[name].js'
};
const rules = [
{
test: /\.js$/,
include: [ JS_DIR ],
exclude: /node_modules/,
// Loaders enable us to bundle the static assets.
use: 'babel-loader', // Allows for transpiling JS files using babel & webpack.
}
];
module.exports = () => ({
entry: entry,
output: output,
devtool: false, // Don't output any .map source files, otherwise 'source-map'.
module: {
rules: rules,
}
});
Currently, when I run npm run prod I get the following build:
It builds the additional /js directory inside the /js directory and then it has main/all.js and main/main.js. The all.js inside there is empty, but the main.js is the compiled stuff.
What I'm trying to achieve:
Instead of building the /js directory inside /js, how can I make the contents of js/main/main.js output to just the all.js in the main js directory? So basically like this:
All help would be appreciated!

Node - Fails to run Webpack bundles

I'm bundling my app using webpack and I'm making sure to specify the target to "node" (otherwise the webpack build fails).
With my current configuration the build is successful, but when I try to run it using node I'm getting an error:
C:\Users\myuser\Desktop\myproject\dist\app.js:20 /******/
modules[moduleId].call(module.exports, module, module.exports,
webpack_require);
^
TypeError: Cannot read property 'call' of undefined
It refers to a line inside of the webpackBootstrap function injected into the beginning of app.js. It feels as though node is not compatible with Webpack, even though from what I understood it should be.
I doubt it's relevant to the issue, but in order for you to have the full picture:
I'm transpiling ts and having each file from src exported as a separate chunk into dist instead of bundling everything together, in order to dynamically import files on demand at runtime.
For instance:
src/app.ts
src/compA.ts
src/compB.ts
will become:
dist/app.js
dist/compA.js
dist/compB.js
Here's my webpack.config.js:
const path = require('path');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const { CheckerPlugin } = require('awesome-typescript-loader');
const glob = require('glob');
let entry = {};
glob.sync('./src/**/*.*').forEach(component => {
let name = component.match(/.*\/(.*)\..*/)[1];
entry[name] = component;
});
module.exports = {
mode: 'development',
entry,
target: 'node',
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx']
},
devtool: 'inline-source-map',
devServer: {
contentBase: './dist'
},
module: {
rules: [
{
test: /\.tsx?$/,
loader: 'awesome-typescript-loader'
}
]
},
plugins: [
new CleanWebpackPlugin(['dist']),
new CheckerPlugin()
],
output: {
filename: (chunkData) => {
let name = chunkData.chunk.name;
let src = chunkData.chunk.entryModule.id;
let path = src.split('/');
let dir = path[path.length -2];
let pathPrefix = dir !== 'src' ? dir + '/' : '';
return pathPrefix + name + '.js';
},
path: path.resolve(__dirname, 'dist'),
publicPath: '/'
},
optimization: {
splitChunks: {
chunks: 'all'
},
},
};
I needed to include node externals in the config.
const path = require('path');
const nodeExternals = require('webpack-node-externals');
module.exports = {
target: "node",
entry: {
app: ["./back.js"]
},
output: {
path: path.resolve(__dirname, "../build"),
filename: "bundle-back.js"
},
externals: [nodeExternals()],
};
https://medium.com/code-oil/webpack-javascript-bundling-for-both-front-end-and-back-end-b95f1b429810

Local JavaScript Files Not Updating - Stencil CLI

I am modifying a purchased stencil-based theme for a client. When I modify javascript files, bundle.js does not update and I do not see a file change in the CLI. I am unable to see my changes on the local site. However, as a test, I was able to modify bundle.js directly and saw my change take place.
I have looked through the BC docs and have asked questions in other forums, but still no solution. I am not getting any errors in the CLI when I start stencil or run the bundle command. I can also upload my theme to the store without error.
Any ideas?
**Edit:
Here are the contents of my stencil.conf.js file:
var path = require('path');
var webpack = require('webpack');
var webpackConfig = require('./webpack.conf.js');
webpackConfig.context = __dirname;
webpackConfig.entry = path.resolve(__dirname, 'assets/js/app.js');
webpackConfig.output = {
path: path.resolve(__dirname, 'assets/js'),
filename: 'bundle.js'
};
/**
* Watch options for the core watcher
* #type {{files: string[], ignored: string[]}}
*/
var watchOptions = {
// If files in these directories change, reload the page.
files: [
'/assets',
'/templates',
'/lang'
],
//Do not watch files in these directories
ignored: [
'/assets/scss',
'/assets/css',
]
};
/**
* Hook into the stencil-cli browsersync instance for rapid development of themes.
* Watch any custom files and trigger a rebuild
* #param {Object} Bs
*/
function development(Bs) {
var compiler = webpack(webpackConfig);
// Rebuild the bundle once at bootup
compiler.watch({}, function(err, stats) {
if (err) {
console.error(err)
}
Bs.reload();
});
}
/**
*/
/**
* Hook into the `stencil bundle` command and build your files before they are packaged as a .zip
* Be sure to call the `done()` callback when finished
* #param {function} done
*/
function production(done) {
var compiler;
webpackConfig.devtool = false;
webpackConfig.plugins.push(new webpack.optimize.DedupePlugin());
webpackConfig.plugins.push(new webpack.optimize.UglifyJsPlugin({
comments: false
}));
compiler = webpack(webpackConfig);
compiler.run(function(err, stats) {
if (err) {
throw err;
}
done();
});
}
module.exports = {
watchOptions: watchOptions,
development: development,
production: production,
};
Here are the contents of my webpack.conf.js file:
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'eval-cheap-module-source-map',
bail: false,
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
include: [
path.resolve(__dirname, 'assets/js'),
path.resolve(__dirname, 'node_modules/#bigcommerce/stencil-utils'),
],
query: {
compact: false,
cacheDirectory: true,
presets: [ ['es2015', {loose: true}] ]
}
}
]
},
plugins: [],
watch: false
};

Categories

Resources