Webpack Usage of chunkFilename - node.js

Iam having trouble understand the use of chunkFilename property. Where do we need it?
I cant find any usage in webpack docs.
const path = require('path');
const config = {
entry:['./util.js','./index.js'],
output: {
path: path.resolve(__dirname, 'public'),
filename: '[name].bundle.js',
chunkFilename: '[name].chunk.js'
},
module: {
rules: [
{ test: /\.js$/, exclude:/node_modules/ }
]
}
};
module.exports = config;

chunkFilename is used for naming chunks :]
Chunks are created using dynamic import such as import('./file') or webpacks require.ensure() syntax.

Related

SVG sprite issue with Laravel Mix

I'm struggled with the following and would appreciate any help...!
I try to use Laravel Mix (v5.0.4) and extend it with SVG sprite loader (svg-sprite-loader) to generate SVG sprite. I have the following folder structure:
resources/
images/
image.jpg
sass/
app.scss
svg/
file1.svg
file2.svg
webpack.sprite.js
webpack.mix.js
The content of webpack.mix.js:
const mix = require('laravel-mix');
require('./webpack.sprite');
const toCss = 'public/css';
mix.sass('resources/sass/app.scss', toCss)
.options({
sassOptions: {
outputStyle: 'nested',
}
})
.sprite();
The content of webpack.sprite.js:
const mix = require('laravel-mix');
const SpriteLoaderPlugin = require('svg-sprite-loader/plugin');
const path = require('path');
class Sprite {
dependencies() {
return ['svg-sprite-loader'];
}
webpackPlugins() {
return new SpriteLoaderPlugin({plainSprite: true});
}
webpackRules() {
return {
test: /\.svg$/,
include: path.resolve(__dirname, 'resources', 'svg'),
use: [
{
loader: 'svg-sprite-loader',
options: {
extract: true,
spriteFilename: path.resolve(__dirname, 'resources', 'images') + 'sprite.svg',
runtimeCompat: true
}
},
'svg-transform-loader',
'svgo-loader'
]
};
}
}
mix.extend('sprite', new Sprite());
It does NOTHING in regards sprite, but it generates the CSS from SASS! :( I don't know why... Tried to "debug" it with some console.log() in the extension and it was hit, I saw the log messages in the console. But the sprite wasn't generated.
I also tried to use just hardcoded, relative paths in the extension without path. Didn't help.
Any idea?
Thanks in advance!
I have a feeling this is related to Webpack5's new Asset module.
https://webpack.js.org/guides/asset-modules/
For assets to be written to disk, or possibly primed to be handed off to large plugins you need to now specify asset type and generator to best define a filename for these assets.
webpackRules() {
return {
test: /\.svg$/,
include: path.resolve(__dirname, 'resources', 'svg'),
type: 'asset/resource',
generator: {
'filename': '[name][ext]'
},
use: [
{
loader: 'svg-sprite-loader',
options: {
extract: true,
spriteFilename: path.resolve(__dirname, 'resources', 'images') + 'sprite.svg',
runtimeCompat: true
}
},
'svg-transform-loader',
'svgo-loader'
]
};
}
If still no luck try an alternative plugin:
https://www.npmjs.com/package/webpack-svg-spritely

Cannot find module "module" - Rewire.js

I am trying to use rewire with my Karma (Webpack + Typescript) unit tests. My unit tests are written in Typescript, bundled with Webpack, and then run with Karma. I keep getting the error:
PhantomJS 2.1.1 (Windows 7 0.0.0) ERROR
Error: Cannot find module "module"
at src/myTest.spec.ts:187
I looked into the code of Rewire, and the problem comes from the line
var Module = require("module"),
I know there is a Webpack Rewire plugin, but when I use it, I have the same problem as that already reported in an issue.
All my tests that don't use rewire work fine.
Here is my test file:
import rewire = require("rewire");
const decorators = rewire("./decorators");
describe('something', () => {
it('should do something', () => {
decorators.__set__('Test', () => 'hello');
// In know this is pointless, but it's just to make sure that rewire works.
expect(decorators.Test).toBe('hello');
});
});
Here is my webpack config:
var webpack = require('webpack');
var path = require('path');
var fs = require('fs');
var nodeModules = {};
fs.readdirSync('node_modules')
.filter(function (x) {
return ['.bin'].indexOf(x) === -1;
})
.forEach(function (mod) {
nodeModules[mod] = 'commonjs ' + mod;
});
// Our Webpack Defaults
var webpackConfig = {
entry: './src/index.ts',
target: 'node',
module: {
loaders: [
{test: /\.ts$/, loaders: ['ts-loader'], exclude: /node_modules/}
]
},
plugins: [
new webpack.BannerPlugin({banner: 'require("source-map-support").install();', raw: true, entryOnly: false}),
new webpack.optimize.UglifyJsPlugin({sourceMap: true}),
new webpack.optimize.AggressiveMergingPlugin(),
],
output: {
path: path.resolve(__dirname, './dist'),
filename: 'index.js',
sourceMapFilename: 'index.map'
},
externals: nodeModules,
devtool: 'source-map',
resolve: {
extensions: ['.ts', '.js']
}
};
module.exports = webpackConfig;
and here is my (the relevant) part of my karma.conf.js:
frameworks: ['jasmine'],
files: [
'src/**/*.spec.ts',
'test/**/*.ts'
],
exclude: [],
webpack: {
devtool: webpackConfig.devtool,
module: webpackConfig.module,
resolve: webpackConfig.resolve,
},
webpackMiddleware: {
quiet: true,
stats: {
colors: true
}
},
preprocessors: {
'src/**/*.spec.ts': ['webpack', 'sourcemap'],
'test/**/*.ts': ['webpack', 'sourcemap']
},
I think you write this wrong
import rewire = require("rewire");
it should be
import rewire from 'rewire'
for ES6
or
const rewire = require('rewire')
for ES5
Rewriting the script in package.json worked for me:
"test": "ts-node -O '{\"module\":\"commonjs\"}' node_modules/jest/bin/jest.js"
If you get the error
SyntaxError: Unexpected token ' in JSON at position 0
this fixed it for me:
ts-node -O \"{\\\"module\\\":\\\"commonjs\\\"}\" node_modules/jest/bin/jest.js
It was not my idea. See this answer to a Github issue for a great explanation.

Webpack bundling doesn't include specific module such as 'sequelize'

I'm developing nodejs with webpack, seqelize and other modules with below webpack configuration.
const path = require('path');
const webpack = require('webpack');
const fs = require('fs');
const glob = require('glob');
const CleanWebpackPlugin = require('clean-webpack-plugin');
var nodeModules = {};
fs.readdirSync('node_modules')
.filter(function(x) {
return ['.bin'].indexOf(x) === -1;
})
.forEach(function(mod) {
nodeModules[mod] = 'commonjs ' + mod;
});
module.exports = {
// entry: [ path.resolve(__dirname, 'server.js'), models ],
entry: glob.sync(path.resolve(__dirname, 'src/**/*.js')),
resolve: {
// Add `.ts` and `.tsx` as a resolvable extension.
root : [path.resolve(__dirname, '')],
extensions: ['', '.webpack.js', '.web.js', '.ts', '.tsx', '.js'],
modulesDirectories: ['node_modules']
},
module: {
loaders: [
{
test: /\.js$/,
loader: 'babel',
exclude: /node_modules/,
query: {
cacheDirectory: true,
presets: ['es2015']
}
}, {
test: /\.json$/,
loader: 'json'
}
]
},
plugins: [
new CleanWebpackPlugin(['build'], {
root: path.resolve(__dirname, ''),
verbose: true,
dry: false,
exclude: [],
watch: true
})
],
node: {
__filename: true,
__dirname: true
},
target: 'node',
externals: nodeModules,
output: {
path: path.resolve(__dirname, 'build'),
filename: 'server.[chunkhash].js',
libraryTarget: 'commonjs'
}
}
In this case, I try to bundle the whole sources with the config and then get the bundled file named server.[chunkhash].js.
I want to move the file to server and just make work with a command like node server.[chuckhash].js, however, I got the message like below.
module.js:472
throw err;
^
Error: Cannot find module 'sequelize'
at Function.Module._resolveFilename (module.js:470:15)
at Function.Module._load (module.js:418:25)
at Module.require (module.js:498:17)
at require (internal/module.js:20:19)
...
So, I tried to find the specific point to make the error, and then found out my models/index.js use the seqelize module for below codes.
import fs from 'fs';
import path from 'path';
import Sequelize from 'sequelize';
import config from 'config/env';
const sequalize = new Sequelize(config.mysql.database, config.mysql.username, config.mysql.password, config.mysql.params.options);
const db = {};
fs.readdirSync(__dirname)
.filter(file => {
return (file.indexOf('.') !== 0) && (file !== 'index.js');
})
.forEach(file => {
const model = sequalize.import(path.resolve(__dirname, file));
db[model.name] = model;
});
Object.keys(db).forEach(modelName => {
if ('associate' in db[modelName]) {
db[modelName].associate(db);
}
});
db.sequelize = sequalize;
db.Sequelize = Sequelize;
export default db;
How could I fix this issue?
Actually, with the nodemodule in the same folder, there has been no error, but, make the bundled file, it will make the error.
You defined all your node_modules as externals (externals: nodeModules,). This means that webpack won't bundle any module that comes from node_modules and will just leave the imports to be resolved at runtime, just like it would when running it in Node without using webpack. For this to work you need to have the modules available wherever you run the bundle.
If you want webpack to bundle the node_modules as well, you can remove the externals option.
The externals config you're using likely came (directly or indirectly) from Backend Apps with Webpack (Part I) and you should read that blog post to understand what it's really doing and whether you need it.

How do I output webpack as a string using Node

I am trying to use Webpack to bundle a bunch of files. I have the following in my node code...
webpack({
entry: "./src/test",
output: {
path: __dirname,
filename: "bundle.js"
},
}, function(err, stats){
console.log("I would like to output the created js here");
})
This works fine creating a file called bundle.js but I can't figure out how to output as a string instead.
Basically what you can do is to read the file, and then work with it as you want.
e.g.
import webpack from 'webpack';
const config = require('../webpack.config');
const compiler = webpack(config);
compiler.run((err, stats) => {
const data = stats.toJson();
const app = data.assetsByChunkName.app[0] //here you can get the file name
// if you don't have chunks then you should use data.assets;
const file = fs.readFileSync('path to your output ' + app); //read the file
//now you can work with the file as you want.
});
//Basic webpack.config.js
module.exports = {
devtool: 'source-map',
entry: {
app: 'Some path' // you can have different entries.
entrie2 : ''
.... more entries
},
output: {
path: 'Some path'
}
}
Hope this help.

got "Element type is invalid: expected a string" when trying to server side rendering react

I get this error:
Invariant Violation: Element type is invalid: expected a string (for built-in components) or a class/function (for composite components) but got: object.
When trying to use ReactDOMServer.renderToStaticMarkup.
This is my react app:
"use strict";
import React from 'react'
module.exports = () => {
return (
<div></div>
);
};
And this is my node server rendering code:
"use strict";
const path = require('path');
const webpack = require('webpack');
const React = require('react'), ReactDOMServer = require('react-dom/server'),
DOM = React.DOM, body = DOM.body, div = DOM.div, script = DOM.script;
webpack({
target: "node",
entry: [
path.resolve(__dirname, '../js', 'app.js'),
],
module: {
loaders: [
{
exclude: /node_modules/,
loader: 'babel',
test: /\.js$/,
},
]
},
output: {filename: 'app.bundle.js', path: __dirname},
},() => {
const App = React.createFactory(require('./app.bundle.js'));
let html = ReactDOMServer.renderToStaticMarkup(body(null,
div({
id: 'root', dangerouslySetInnerHTML: {
__html: ReactDOMServer.renderToString(App())
}
})
));
});
Does anyone have an idea what cause this error and how to fix this?
Thanks in advance.
It appears that the bundle is not compatible by default with commonjs. As I read in webpack docs, you need to add libraryTarget:'commonjs2' to your output object in order to do it.
Like this:
output: {filename: 'app.bundle.js', path: __dirname,libraryTarget:'commonjs2'}

Resources