How can I get webpack to emit its output to two locations? - javascript

My current configuration is as follows:
output: {
filename: 'bundle.js',
path: OUT_DIR
},
However I need bundles.js to go to two directories?
Can I accomplish this by simply passing an array of directories to path?
Or do I need to do something more complex?
Currently I have a bash script cpll which I have to type in manually after each build and it is tedious.
Hopefully web pack has a configuration option to send the output to two or more locations.
Research
google search
This SO question is 4 years old and does not have what I am lookin for - so
The documentation does not mention a way to do it here - webpack.
If there is not a configuration option how can I have it run a bash command automatically?
I tried passing it an array of strings instead of a string and it crashed with the obvious error:
Invalid configuration object. Webpack has been initialised using a
configuration object that does not match the API schema.
- configuration.output.path should be a string.
Passing an array will not work. Hmmm.
Trying another approach starting with a google - search
Brings up a possible solution - so
per request - complete exportFunc
const exportFunc = ( env ) => {
console.log('webpack.config.js-exportFunc', OUT_DIR);
return {
entry: `${IN_DIR}/index.jsx`,
output: {
filename: 'bundle.js',
path: '/Users/c/_top/ll-front/dist'
},
module: {
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
},
{
test: /\.jsx?/,
include: IN_DIR,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env', '#babel/preset-react'],
plugins: ['#babel/plugin-proposal-object-rest-spread', '#babel/plugin-proposal-class-properties'],
}
}
}
]
}
};
};
module.exports = exportFunc;

You can use webpack's multi-compiler mode by exporting an array of configs.
As in the docs:
Instead of exporting a single configuration object/function, you may export multiple configurations (multiple functions are supported since webpack 3.1.0). When running webpack, all configurations are built.
For example:
const config = {
// your webpack config
}
const outputPaths = ["path/one", "path/two"]
module.exports = outputPaths.map(outputPath => {
return {
...config,
name: outputPath,
output: {
...config.output,
path: path.resolve(__dirname, outputPath)
}
}
})
As you're using a function config you can do something like this:
const outputPaths = ["path/one", "path/two"]
module.exports = outputPaths.map(outputPath => {
return env => {
return {
entry: `${IN_DIR}/index.jsx`,
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, outputPath)
},
module: {
rules: [
{
test: /\.css$/,
use: [ 'style-loader', 'css-loader' ]
},
{
test: /\.jsx?/,
include: IN_DIR,
use: {
loader: 'babel-loader',
options: {
presets: ['#babel/preset-env', '#babel/preset-react'],
plugins: ['#babel/plugin-proposal-object-rest-spread', '#babel/plugin-proposal-class-properties'],
}
}
}
]
}
};
}
})

You could use multiple configurations instead. Here's the webpack documentation link.
To avoid code duplicaion consider your current config as an object. Then duplicate that object and override the output section of the duplicated object. Finally put both objects into an array. Use that array as your new config.
var yourCurrentConfig = {...};
var secondaryDestinationConfig = Object.assign(yourCurrentConfig, {
output: {
path: {
filename: 'bundle.js',
path: SECONDARY_DIR
}
}
});
var newConfig = [
yourCurrentConfig, secondaryDestinationConfig
];

Related

How to merge bundles with webpack

I'm developing a few React components with the intention of adding them to our Webflow site. For that, I've added an entry for each component in my webpack.config.js file. Now, it looks like this:
const path = require("path");
module.exports = {
entry: {
component_a: "./src/components/a.js",
component_b: "./src/components/b.js",
component_c: "./src/components/c.js",
},
mode: "production",
module: {
rules: [
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
use: ["babel-loader"]
},
{
test: /\.css$/,
use: ["style-loader", "css-loader"]
},
{
test: /\.(pdf|jpg|png|gif|svg|ico)$/,
use: [
{
loader: "url-loader"
}
]
},
{
test: /\.(woff|woff2|eot|ttf|otf)$/,
loader: "file-loader"
}
]
},
resolve: {
extensions: ["*", ".js", ".jsx"]
},
output: {
path: __dirname + "/dist",
publicPath: "/",
filename: "bundle_[name].js"
},
devServer: {
static: {
directory: path.join(__dirname, "dist")
}
}
};
This generates me a few bundle_<component_name>.js files, which works great!
But then, there was a need of adding react-map-gl for some of those components, and that's where the issue began: I was having an issue with react-map-gl when doing npm run build and this solved it. But at the same time, a new bundle_mapbox-gl-csp-worker.worker.js is generated for me and all of my built components that depend on it have something like this:
{return new Worker(i.p+"bundle_mapbox-gl-csp-worker.worker.js")}
Although it works fine for our container deployment (because it will always look for bundle_mapbox-gl-csp-worker.worker.js on the same origin and this file will exist), whenever I try to add <script src="https.../bundle_my_component.js"> to Webflow, it will look for https://my-webflow.domain/bundle_mapbox-gl-csp-worker.worker.js, which doesn't exist.
I've tried to replace i.p+"bundle_mapbox-gl-csp-worker.worker.js" to somewhere this script is known to exist, but then I get Script at 'https://.../bundle_mapbox-gl-csp-worker.worker.js' cannot be accessed from origin 'https://some.other.origin'.
I wonder if there's a way of merging my component and the bundle_mapbox-gl-csp-worker.worker.js somehow, either through webpack or something. Or any other workaround for this.

configure Laravel mix mix.webpackConfig({}) with entry points and outputs

I'm developing an application that use php 5.6 and laravel 5.4. I'm using laravel mix for build my assets. I need to know how to use mix.webpackConfig({}) method to use another webpack configurations like use babel-loader, riot-tag-loader etc. Is there any way to use this method to do that with entry point and output files? For an example, I need to do following thing inside my mix.webpackConfig({}).
module.exports = {
entry: {
admin: ['./resources/assets/admin/js/app.js'],
'manuals/parent/child/js': ['./resources/views/manuals/parent/child/js/app.js']
},
output: {
filename: '[name]/app.js',
path: path.resolve(__dirname + '/public')
},
module: {
rules: [
{
test: /\.tag$/,
exclude: /node_modules/,
loader: 'riot-tag-loader',
query: {
type: 'es6',
hot: true
}
},
{
test: /\.js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader'
}
}
]
}
};
Is that possible? Is that so, please let me know how to do that. Thanks
I've hardly found the laravel-mix mix.webpackConfig({}) successfully initiated, and even working samples are rear. I do not know what framework you are trying to manage but this sample works; this is a config for less-loader, hope you can tune it to suit your purpose.
const path = require('path');
mix.webpackConfig({
module: {
rules: [
{
test: /\.less$/,
loader: "style-loader!css-loader!less-loader",
exclude: [
path.resolve(__dirname, "node-modules"),
path.resolve(__dirname, "resources/assets/less"),
],
},
]}
})
Mix is a configuration layer on top of Webpack, so to run your Mix tasks you only need to execute one of the NPM scripts that is included with the default Laravel package.json file: more details in official site
https://laravel.com/docs/5.7/mix

Webpack - Folder Access Outside Application Folder

I have code base, the folder structure for which looks like this :
|- build\
|- node_modules\
|- apps\
|--- app_no_1\
|----- index.js
|- src\
|--- modules\
|----- form-login\
|------- Form.jsx
|- package.json
|- webpack.config.js
....
The app_no_1\ folder holds the index file for its React app. However, the modules are sat within the src\ folder. When I import the component from the src directory into the app, I get the error:
bundle.js:41448 Uncaught Error: Module parse failed: Unexpected token (15:18)
You may need an appropriate loader to handle this file type.
| // );
Is there some webpack configuration option I am missing which is required for access to files outside the app's folder? My webpack.config.js is this:
const path = require('path');
const merge = require('merge');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const PATHS = {
app: path.join(__dirname, 'apps'),
appAthenaTrader: path.join(__dirname, 'apps/athenaTrader'),
appAthenaFinancier: path.join(__dirname, 'apps/athenaFinancier'),
build: path.join(__dirname, 'build'),
modules: path.join(__dirname, 'src/modules')
};
const common = {
output: {
path: PATHS.build,
publicPath: '/',
filename: 'bundle.js'
},
resolve: {
alias: {
modules: PATHS.modules
},
extensions: ['.js', '.jsx', '.json'],
modules: [PATHS.modules, 'node_modules']
},
module: {
rules: [
{
test: /\.jsx?$/,
include: PATHS.app,
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true
}
}
]
},
{
test: /\.scss$/,
include: PATHS.app,
use: [
{
loader: 'style-loader'
},
{
loader: 'css-loader'
},
{
loader: 'sass-loader'
}
]
},
{
test: /\.(jpg|png)$/,
include: PATHS.app,
use: {
loader: 'file-loader?name=[name].[ext]'
}
}
]
},
plugins: [
new HtmlWebpackPlugin({
title: 'Satoshi Ltd - Athena'
})
]
};
const generateEntry = env => {
const entryVariable = {
entry: {
app: ''
}
};
if (env.app === 'athena-trader') {
entryVariable.entry.app = PATHS.appAthenaTrader;
} else if (env.app === 'athena-financier') {
entryVariable.entry.app = PATHS.appAthenaFinancier;
// } else ...
}
return entryVariable;
};
const devServer = {
devServer: {
stats: 'errors-only',
host: process.env.HOST || 'localhost',
port: process.env.PORT || 3000
},
devtool: 'inline-source-map'
};
const generateConfig = env => {
const entry = generateEntry(env);
if (env.profile === 'development') {
return merge(common, entry, devServer);
}
return merge(common, entry);
};
module.exports = generateConfig(process.env);
I should note that when the folder is brought inside the app_no_1, the app functions fine, i.e. it is able to execute the component & display it. However, the above folder structure is not being accepted for the apps.
The issue is in your babel-loader configuration. Webpack is complaining that it doesn't know how to parse your files (I'm assuming it's JSX).
In your configuration, you have:
module: {
rules: [
{
test: /\.jsx?$/,
include: PATHS.app,
use: [
{
loader: 'babel-loader',
options: {
cacheDirectory: true
}
}
]
},
// ...
]
include tells webpack to use babel-loader on any files located inside PATHS.app. When it looks at your files located in PATHS.modules, it doesn't use babel-loader. This is when webpack shows that Module parse failed error.
To fix this, you can update your include value to something like this:
include: [PATHS.app, PATHS.modules]
An alternative is to use exclude instead of include.
// assuming you want to only ignore node_modules
exclude: /node_modules/
I also made a barebones example of this on Github.

Typescript: How to have some imports in the global scope?

Context:
I work on a project where the senior programmer decided to reduce the boilerplate code in newly created typescript files. Two examples of this boilerplate code would be importing the React library or the function that fetches and processes our localized strings.
Question:
Is it possible to have imports always available in files placed in certain folders without having to write the import tags every time?
What I've tried:
I've searched and read on the subject and found those links that talk about defining variables to use in the global space:
global.d.ts, global-modifying-module.d.ts, A typescript issue that seems to get it working
However, I was still unable to get it to work. Here is what I've tried:
At the root of the folder where I want React to be always available, I created a global.d.ts file which contains:
import * as R from "react";
declare global{
const React: typeof R;
}
With this file, the resource "React" is supposed to always be available to other files in subsequent folders. My IDE (Webstorm) recognizes that the import is there and allows me to manipulate the variable React without complaining. However, when I try to run the app, I get this error:
ReferenceError: React is not defined
I don't understand what is wrong with the code! Here is an example of the file I'm trying to render:
export default class World extends React.Component<{}, any> {
public render() {
return (<div>Hello world</div>);
}
}
From this stackoverflow question, I was under the impression that the problem could be webpack related. For the sake of completeness, here is the webpack config file we're currently using:
const webpack = require('webpack');
const path = require('path');
const BUILD_DIR = path.resolve(__dirname, './../bundles');
const WEBPACK_ENTRYFILE = path.resolve(__dirname, './../srcReact/ReactWrapper.tsx');
// `CheckerPlugin` is optional. Use it if you want async error reporting.
// We need this plugin to detect a `--watch` mode. It may be removed later
// after https://github.com/webpack/webpack/issues/3460 will be resolved.
const { CheckerPlugin } = require('awesome-typescript-loader');
const config = {
entry: [WEBPACK_ENTRYFILE],
resolve: {
extensions: ['.ts', '.tsx', '.js', '.jsx', '.less']
},
output: {
path: BUILD_DIR,
filename: 'bundle.js'
},
plugins: [
new CheckerPlugin()
],
devtool: 'source-map', // Source maps support ('inline-source-map' also works)
module: {
loaders: [
{
loader: 'url-loader',
exclude: [
/\.html$/,
/\.(js|jsx)$/,
/\.(ts|tsx)$/,
/\.css$/,
/\.less$/,
/\.ttf/,
/\.woff/,
/\.woff2/,
/\.json$/,
/\.svg$/
],
query: {
limit: 10000,
name: 'static/media/[name].[hash:8].[ext]'
}
},
{
loader: 'url-loader',
test: /\.(ttf|woff|woff2)$/
},
{
loader: "style-loader!css-loader!less-loader",
test: /\.less$/
},
{
loader: "style-loader!css-loader",
test: /\.css$/
},
{
loader: "svg-loader",
test: /\.svg$/
},
{
loader: "json-loader",
test: /\.json$/
},
{
loader: "awesome-typescript-loader",
test: /\.(ts|tsx)$/
}
]
}
};
module.exports = config;
I am certain I am missing something. Can anyone help me?
Surely already open followed a tutorial like this
To do this creates a vendor file where you import these types of "global".
./src/vendors.ts;
import "react";
Add this file a to first place at entry parameter:
entry: { 'vendors': './src/vendors.ts', 'main': './src/main.ts' }
And add CommonChunkPlugins:
plugins: [ new CommonsChunkPlugin({
name: 'vendors'
}),
Like this in AngularClass with polyfills.

What does this single line of webpack html loader syntax mean?

To solve a problem I was having with my webpack.config.js file I copied a line from a webpack blog. The line is starred in the code below. However I can't seem to easily figure out what the line is doing and googling didn't lead me to a simple explanation. So, what is the purpose/syntax of the indicated line? A short explanation would probably suffice, but a link to some (official) documentation would also be helpful.
var path = require('path');
module.exports = {
entry: {
javascript: ['babel-polyfill', './src/main.js'],
html: './index.html'
},
output: {
path: path.join(__dirname, 'build'),
filename: 'bundle.js'
},
devtools: 'inline-source-map',
module: {
loaders: [
{
loader: 'babel-loader',
test: path.join(__dirname, 'src'),
query: {
presets: ['react', 'es2015', 'stage-2']
}
},
{
test: /\.html$/,
loader: 'file?name=[name].[ext]' // <---- **********
}
]
}
};
The webpack file loader lets you specify a custom filename template for imported files using the name= query parameter:
https://github.com/webpack/file-loader#filename-templates
Webpack 1 supports configuring a loader entirely through a query-string like DSL. Written in the alternative syntax for configuration makes it clear(er) what is going on:
{
test: /\.html$/,
loader: 'file', // Use the file loader
query: { // Configuring it with the following options
name: '[name].[ext]'
// Set the name of the HTML files that are output to be
// the local name of the file, followed by a literal dot character
// followed by the file's extension.
}
}

Categories