how to add hooks after bundle update - node.js

EDIT:I need to directly generate <script type="text/javascript" src="..."></script> format to a text file which my web app(django or rails) template engine can directly include. So a json file seems not ok.
After webpack update the js file in webpack --progress --colors --watch mode, I want to :
Create a copy with hashed-filename to specified path.
execute some nodejs code that lists all filenames in specified directory and writes them to a text file.
Currently my config file is:
module.exports = {
entry: "./index.js",
output: {
path: __dirname,
filename: "bundle.[hash].js"
},
module: {
loaders: [
{ test: /\.css$/, loader: "style!css" },
{ test: /\.scss$/, loaders: ["style", "css", "sass"]},
],
}
};
For example, every time webpack generate a bundle.[hash].js file, it will first make its copy to /bar, then check all filenames in /bar and write these filenames to /foo/bar/js.txt in this format:
<script type="text/javascript" src="/bar/bundle.sdfklsld.js"></script>
<script type="text/javascript" src="/bar/bundle.jkljsdfd.js"></script>
I know this maybe done by bundle-update, but it's poorly documented.

assets-webpack-plugin will be solution for you.
Your webpack.config.js with this plugin should look something like this:
const path = require('path');
const AssetsPlugin = require('assets-webpack-plugin');
const assetsPluginInstance = new AssetsPlugin({
path: path.join(__dirname, 'foo', 'bar'),
filename: 'js.json'
});
module.exports = {
entry: "./index.js",
output: {
path: path.resolve(__dirname, 'bar'),
filename: "bundle.[hash].js"
},
module: {
loaders: [
{ test: /\.css$/, loader: "style!css" },
{ test: /\.scss$/, loaders: ["style", "css", "sass"]},
],
},
plugins: [
assetsPluginInstance
]
};
Now in path bar/ you should have file bundle.sdfklsld.js.
In file foo/bar/js.json you will have:
{
"main": {
"js": "/bar/bundle.sdfklsld.js"
}
}
From that point you are good to go and create your script tags with proper path to bundle files.
Edit - create file .txt with script tags
If you want to create your assets as a plain text file you can use processOutput method in assets-webpack-plugin.
const assetsPluginInstance = new AssetsPlugin({
path: path.join(__dirname, 'foo', 'bar'),
filename: 'js.txt', // change to .txt
// it can be little different in your scenario
// - currently I'm showing only one file,
// but you can tweak it to accept array of files
processOutput: function (assets) {
return `<script type="text/javascript" src="${assets.main.js}"></script>`;
}
});

Related

How to configure Webpack to not pull content of imported Sass files to a source map?

I have a Sass file that imports Bootstrap and Font Awesome.
They has been put on the of the file before my custom CSS class.
Here is the code:
/src/scss/site.scss
#import "~bootstrap/scss/bootstrap";
#import "~font-awesome/scss/font-awesome";
// Custom style sheet here
.my-custom-header{
color:#F00
}
There is a source map after Webpack build but it includes the content of Bootstrap and font awesome.
Here what is look like in Browser:
When I tried to inspect a custom class it point to correct line number of origin source code but incorrect for generated source map because it has content of Bootstrap in the top.
My question is:
Is it possible to configure a output source map to keep the import statement and the content is exact the same as actual source code.
Here what source map I'm expected.
site.css.map
#import "~bootstrap/scss/bootstrap";
#import "~font-awesome/scss/font-awesome";
// Custom style sheet here
.my-custom-header{
color:#F00
}
Here my Webpack configuration:
const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const siteFile = [__dirname, 'src', 'scss', 'site'];
const outputPath = [__dirname, 'public', 'css'];
module.exports = {
entry: {
site: path.resolve(...siteFile),
},
output: {
path: path.resolve(...outputPath),
},
resolve: {
// https://github.com/webpack/webpack-dev-server/issues/720#issuecomment-268470989
extensions: ['.scss']
},
devtool: 'source-map',
module: {
rules: [
{
test: /\.scss$/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader', // Translates CSS into CommonJS modules
options: {
sourceMap: true
}
},
{
loader: 'postcss-loader', // Run post css actions
options: {
plugins: () => {
// post css plugins, can be exported to postcss.config.js
return [
require('precss'),
require('autoprefixer')
];
},
sourceMap: true
}
},
{
loader: 'resolve-url-loader',
},
{
loader: 'sass-loader', // Compiles Sass to CSS, using node-sass by default
options: {
sourceMap: true
}
}
],
exclude: /node_modules/
},
{
test: /\.(png|jpe?g|gif|svg|eot|ttf|woff2?)$/,
use: [
{
loader: 'file-loader',
options: {
name: '[name].[ext]',
outputPath: '.' //relative to output
}
}
]
}
]
},
plugins: [
new MiniCssExtractPlugin({
filename: './[name].css' // relative to output
}),
],
devServer: {
contentBase: path.join(__dirname, 'public'),
compress: false,
port: 8080,
}
};
Here is a link to a repository of the example code.
codesanook-examples-webpack
Thank you.
Have you tried SourceMapDevToolPlugin?
https://webpack.js.org/plugins/source-map-dev-tool-plugin/
You might need to create a vendor bundle for node modules stuff then you can ignore it from sourcemap.

Migrating RequireJS/AMD with Plugins to Webpack

I'm working on migrating a large RequireJS application to Webpack. The basic build with Webpack seems to work fine -- I've moved "paths" definitions to "alias" and I've setup loaders for my content and shims, like jQuery.
However, there's a remaining issue I'm not sure how to resolve. Basically the RequireJS app uses the "text-plugin" to include HTML templates, and Webpack is throwing "Module not found" errors for the HTML templates.
An example AMD module I want to bundle looks something like this:
AMD Module with Text Plugin
define([
'security',
'modals',
'text!../templates/contact_info.html'
], function(security, modals, contactInfoTemplate) {
return {
foo: function() { return "bar"; }
};
});
I thought I could use the raw-loader to load the template files. I aliased 'text' to be the 'raw-loader':
text: {
test: /\.html$/,
loader: "raw-loader"
},
However, I'm seeing the following error for all of my templates that are required like above:
Module not found: Error: Can't resolve 'text'
BREAKING CHANGE: It's no longer allowed to omit the '-loader' suffix when using loaders. You need to specify 'text-loader' instead of 'text'.
I tried replacing 'text!...' with 'text-loader!...', and I then see this error complaining that it can't load/find the HTML module!
Module not found: Error: Can't resolve '../templates/contact_info.html'
webpack.config.js, version 3.9.1
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const path = require('path');
const webpack = require('webpack');
let basePath = path.join(__dirname, '/');
module.exports = {
entry: {
'main': basePath + 'js/main.js',
},
context: __dirname,
output: {
path: __dirname + '/build',
filename: '[name].min.js',
libraryTarget: 'amd',
umdNamedDefine: true
},
module: {
rules: [
{
test: /(\.js)$/,
exclude: /(node_modules)/,
use: {
// babel-loader to convert ES6 code to ES5 + amdCleaning requirejs code into simple JS code, taking care of modules to load as desired
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env'],
plugins: []
}
}
},
{
test: /\.css$/,
use: [
{ loader: "style-loader" },
{ loader: "css-loader" }
]
},
{ test: /\.jpg$/, use: [ "file-loader" ] },
{ test: /\.png$/, use: [ "url-loader?mimetype=image/png" ] },
{
test: /\.(html)$/,
use: {
loader: 'raw-loader',
options: {
minimize: true
}
}
}
]
},
resolve: {
modules: [
'js/**/*.js',
'node_modules',
path.resolve('./js')
],
extensions: ['.js'], // File types,
alias: {
text: {
test: /\.html$/,
loader: "raw-loader"
},
bridge: 'libs/bridge',
cache: 'libs/cache',
cards: 'libs/cards',
moment: 'libs/moment',
underscore: 'libs/underscore',
}
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
filename: 'index.html',
template: '../index.html'
}),
new webpack.ProvidePlugin({
$: 'jquery',
jQuery: 'jquery'
})
]
};
Anyone know how to get Webpack to play nicely with the RequireJS Text plugin?
Thanks!
Maybe try installing text-loader?
In order for something like 'text!../templates/contact_info.html' to "load" properly, since it is not JS, you need to install text-loader to get webpack to understand the syntax text!.
npm install text-loader --save-dev
humm...i just installed text-loaded and it seems we also have to change text! to text-loader!

Webpack not including all our js and jsx file, even those in the same directory

We are trying to upgrade our React.js application which uses WebPack to build. In our upgrades we are moving from Webpack 1.0 to 2.0 and I have made the "necessary" changes for the upgrade. It is building, and compiling, however, when I look at the files included, it is a very smaller scale of the files it was including before.
For instance, we have 34 files in our React Flux Actions directory. Some files have .js extension some .jsx. However, of the 34 files, only 1 is showing up in the build. What happened to the other 33. This one has .js extension but there are more .js files in that directory too.
What am I missing?
This is our main config file.
var path = require('path');
var webpack = require('webpack');
var StringReplacePlugin = require("string-replace-webpack-plugin");
var Environment = require('./js/environment');
module.exports = {
entry: [
'./js'
],
output: {
path: path.join(__dirname, 'build'),
filename: 'bundle.js',
},
plugins: [
new StringReplacePlugin(),
new webpack.LoaderOptionsPlugin({
options: {
tslint: {
emitErrors: true,
failOnHint: true
}
}
})
],
resolve: {
extensions: ['*', '.js', '.jsx'],
modules: [
path.join(__dirname, 'node_modules'),
path.join(__dirname, 'js'),
path.join(__dirname, 'jsx')
]
},
module: {
loaders: [{
test: /\.jsx?$/,
exclude: /node_modules/,
loaders: ['react-hot-loader/webpack', 'babel-loader' ]
},
{
test: /js\/constants.js$/,
loader: StringReplacePlugin.replace({
replacements: [{
pattern: /localhost/g,
replacement: Environment.getBackendURL
}]
})
}]
}
};
This is our hot reload local version, I think both files are used, the one above and this one. But I am only doing "npm run build" command right now, then running "npm run local"
var path = require('path');
var webpack = require('webpack');
module.exports = {
devtool: 'eval',
entry: [
'webpack-dev-server/client?http://localhost:3000',
'webpack/hot/only-dev-server',
'./js/index'
],
output: {
path: path.join(__dirname, 'build-hot'),
filename: 'bundle.js',
publicPath: '/build/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
// new webpack.NoErrorsPlugin()
new webpack.LoaderOptionsPlugin({
options: {
tslint: {
emitErrors: true,
failOnHint: true
}
}
})
],
resolve: {
extensions: ['*', '.js', '.jsx'],
modules: [
path.join(__dirname, 'node_modules'),
path.join(__dirname, 'js'),
path.join(__dirname, 'jsx')
]
},
module: {
loaders: [{
test: /\.jsx?$/,
exclude: /node_modules/,
loaders: ['react-hot-loader/webpack', 'babel-loader' ]
}]
}
};
Based on Michael's answer below, there is one I did find that is different and feels like could be the reason, but I did not see anything in Webpack2 for pre-loaders. Here is it.
preLoaders: [
{
test: /\.jsx?$/,
loader: "source-map-loader"
}
],
Webpack starts looking at your entry point(s) and only includes files that are being imported, it doesn't just include every file in your project (as described in Concepts - Entry of the official docs).
As your entry point is ./js it will start with ./js/index.js (that's how Node.js and therefore webpack handles importing Folders as Modules), so you're not including every file in that directory. And if you don't import them in ./js/index.js or in its dependencies, the files won't be included at all. Presumably you don't and that's why only this one file is being included in the bundle.
This behaviour hasn't changed from webpack 1 to webpack 2. It's rather surprising that it worked differently with webpack 1, but maybe you changed something in the migration process that you aren't aware of.

Webpack file loader not creating or copying files in dist

Hey guys (using webpack 2.1.0-beta.22) so I have the following config in my webpack.base.js:
entry: {
client: "./client/index.js"
},
output: {
path: _.outputPath,
filename: '[name].js',
publicPath: '/themes/default/dist/'
},
module: {
loaders: [
{
test: /\.(ico|jpg|png|gif|eot|otf|webp|svg|ttf|woff|woff2)(\?.*)?$/,
loader: 'file',
query: {
name: 'media/[name].[hash:8].[ext]'
}
}
]
}
And this in my webpack.dev.js:
const cssImagePath = path.resolve('../..');`
base.module.loaders.push(
{
test: /\.(s?)css$/,
loaders: [
'style-loader',
`css-loader?sourceMap&root=${cssImagePath}`,
'sass-loader?outputStyle=expanded&sourceMap&sourceMapContents'
]
}
)
Now I have this line in my scss file: background-image: url('/themes/default/client/images/snow-flake.png');
If I run webpack and use the inspector the path is being replaced to this: url(/themes/default/dist/media/snow-flake.0af467e3.png)
Which looks perfect problem is the file-loader is not creating / copying to that directory so themes/default/dist/media does not exist?
Anyone came across this?

using webpack on server side of nodejs

I've been trying to use webpack with a nodejs application, and the client side is going fine - a reasonably good documentation on their website + links from google search.
Has anyone used webpack on server side of nodejs? or please guide me to any useful links.
Thanks.
This might be useful: http://jlongster.com/Backend-Apps-with-Webpack--Part-I
Key point is to make external all third party module (in node_modules directory) in webpack config file
Final config file
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;
});
module.exports = {
entry: './src/main.js',
target: 'node',
output: {
path: path.join(__dirname, 'build'),
filename: 'backend.js'
},
externals: nodeModules,
plugins: [
new webpack.IgnorePlugin(/\.(css|less)$/),
new webpack.BannerPlugin('require("source-map-support").install();',
{ raw: true, entryOnly: false })
],
devtool: 'sourcemap'
}
A real example with webpack 2.x
I want to highlight the difference from client side config:
1. target: 'node'
2. externals: [nodeExternals()]
for node.js, it doesn't make much sense to bundle node_modules/
3. output.libraryTarget: 'commonjs2'
without this, you cannot require('your-library')
webpack.config.js
import nodeExternals from 'webpack-node-externals'
const config = {
target: 'node',
externals: [nodeExternals()],
entry: {
'src/index': './src/index.js',
'test/index': './test/index.js'
},
output: {
path: __dirname,
filename: '[name].bundle.js',
libraryTarget: 'commonjs2'
},
module: {
rules: [{
test: /\.js$/,
use: {
loader: 'babel-loader',
options: {
presets: [
['env', {
'targets': {
'node': 'current'
}
}]
]
}
}
}]
}
}
export default [config]
Here is the webpack configuration I have used to in my Nodejs application when I wanted it to read JSX which as you know, Node cannot do.
const path = require('path');
module.exports = {
// inform webpack that I am building a bundle for nodejs rather than for the
// browser
target: 'node',
// tell webpack the root file of my server application
entry: './src/index.js',
// tells webpack where to put the output file generated
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'build')
},
// tells webpack to run babel on every file it runs through
module: {
rules: [
{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
options: {
presets: [
'react',
'stage-0',
['env', { targets: { browsers: ['last 2 versions'] } }]
]
}
}
]
}
};
After you implement this though, don't forget to head over to your package.json file and include this script:
{
"name": "react-ssr",
"version": "1.0.0",
"description": "Server side rendering project",
"main": "index.js",
"scripts": {
"dev:build:server": "webpack --config webpack.server.js"
},

Resources