How to handle resources like images in your own node package - javascript

I am developing a webapp with NodeJS and webpack. It uses also ReactJS as a dependency. So let's call it simple ui webapp.
In my package.json I reference a package as a dependency which I want to use in the app. This package is not from npm, but it is developed by myself and resides on the same filesystem, local, which totally works fine. I am developing this package, lets call it ui-elements and the webapp in parallel, because I know I have to use the ui-elements in 10 about following webapp-style projects.
Back to the problem: The package gets imported when I npm install, so I have my local package inside the node_modules dir. Good.
This ui-elements-package is also bundled with webpack and contains some React components that use images as background images. Now, when I run ./node_modules/.bin/webpack inside the package folder (while developing the ui-elements package) the file-loader emits the resources into the res/ folder, like I want it to be in the webpack.config.js from the ui-elements package.
But since I want to use the ui-elements package inside my webapp, the resources reside deep inside the node_modules/ dir (node_modules/ui-elements/res).
My question:
How should my webpack.config.js in the webapp project be altered, to get the image resolving by the browser working?
And, am I thinking too complicated? I just want to build and use a package (containing some ui elements with background images), that i can reuse in React webapps. Is there a better approach?
I will paste the extracts of the webpack configs of both projects:
ui-elements
webpack.config.js
const path = require('path');
module.exports = {
entry: './src/index.js',
output: {
filename: 'index.js',
libraryTarget: 'commonjs2',
path: __dirname
},
module: {
rules: [
{
test: /\.jsx?$/,
include: path.resolve(__dirname, 'src'),
exclude: path.resolve(__dirname, 'node_modules'),
use: [
'babel-loader'
]
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
},
{
test: /\.(jpe?g|png|gif|svg)$/i,
use: [
{
loader: 'file-loader',
options: {
name: 'res/img/[name].[ext]'
}
}
]
}
]
},
resolve: {
extensions: ['.js', '.jsx'],
modules: [
path.resolve(__dirname, 'src'),
path.resolve(__dirname, 'node_modules')
],
}
};
webapp
webpack.config.js
const path = require('path');
module.exports = {
entry: './index.js',
output: {
filename: 'webapp.bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [
{
test: /\.jsx?$/,
exclude: path.resolve(__dirname, 'node_modules'),
use: [
'babel-loader'
]
},
{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}
]
},
resolve: {
/*
* this entry makes me use a local working tree of the
* ui-elements package, which makes working easier, i don't
* have to switch projects, rebuild the package and update my
* dependencies in this webapp project
*/
/*
alias: {
"ui-elements": path.resolve(__dirname, 'libDev'),
},
*/
extensions: ['.js', '.jsx'],
modules: [
path.resolve(__dirname, 'src'),
// path.resolve(__dirname, 'libDev'),
path.resolve(__dirname, 'node_modules')
],
}
};

Related

Building an AngularJS and Vue.js into one app using webpack?

This may seem a bit convoluted, and potentially the answer is "don't do it that way, do it this way" so I'll start with the background of what I am doing. Basically I have a legacy AngularJS app that we want to migrate away from and towards Vue. We do not have the option to end-to-end rewrite the app, and need to do it piece by piece whilst still delivering a functional app.
The general goal is to therefore have both frameworks running simultaneously, my hope is that I can either do something with the routing or potentially split my single page app into 2 seperate pages for the different fraweworks. I have converted the angularjs from using a gulp build pipeline to using webpack as I assumed this was a logical first step to getting Vue to run, but now I have hit a road block.
My working webpack.config.js for building the angular app looks like the following:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
target: 'web',
// mode: "development",
// devtool: "source-map",
module: {
rules: [
{
test: /\.html$/,
loader: "html-loader",
},
{
test: /\.s[ac]ss$/i,
use: [
"style-loader",
"css-loader",
"sass-loader",
],
},
{
test: require.resolve("jquery"),
loader: "expose-loader",
options: {
exposes: ["$", "jQuery"],
},
}
],
},
entry: {
vendor: "./source/vendor.js",
main: "./source/index.js",
},
optimization: {
minimize: false
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'distribution'),
clean:true
},
plugins: [
new HtmlWebpackPlugin({
template: 'source/index.html',
})
]
};
this now works fine and I get something out add the end that works as it did before.
I then added a /source/vueJs directory, and copy & pasted the content hello world project that is generated by vue create hello-world. My assumption was if I could modify my webpack.config.js to build this, I could then iterate on it further to get to a point where it merged the two working apps together, but I'm already struggling to get the hello-world vue project to produce anything.
So far I basically commented out all the relevant angularJS parts, and added what I thought was correct to get the vue app to build, so now I have this:
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { VueLoaderPlugin } = require('vue-loader')
module.exports = {
target: 'web',
mode: "development",
devtool: "source-map",
module: {
rules: [
// {
// test: /\.html$/,
// loader: "html-loader",
// },
// {
// test: /\.s[ac]ss$/i,
// use: [
// "style-loader",
// "css-loader",
// "sass-loader",
// ],
// },
// {
// test: require.resolve("jquery"),
// loader: "expose-loader",
// options: {
// exposes: ["$", "jQuery"],
// },
// },
{
test: /\.(png|jpe?g|gif)$/i,
use: [
{
loader: 'file-loader',
},
],
},
{
test: /\.vue$/,
loader: 'vue-loader'
},
// this will apply to both plain `.js` files
// AND `<script>` blocks in `.vue` files
{
test: /\.js$/,
loader: 'babel-loader'
},
// this will apply to both plain `.css` files
// AND `<style>` blocks in `.vue` files
{
test: /\.css$/,
use: [
'vue-style-loader',
'css-loader'
]
}
],
},
entry: {
// vendor: "./source/vendor.js",
// angular: "./source/index.js",
vue: "./source/vueJs/index.js"
},
optimization: {
minimize: false
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'distribution'),
clean:true
},
plugins: [
new HtmlWebpackPlugin({
//template: 'source/index.html',
}),
new VueLoaderPlugin()
],
};
this runs fine and I get a distribution/ directory with my assets in, but the served site runs as if there is no javascript running at all. Comparing the output of npx webpack on my version and the output of npx vue-cli-service build on the hello-world project, the javascript is similar but different in a lot of key areas, for a start it seems as though my version does not have any HTML embedded in it like the hello world project does.
Is it a lost cause trying to compile a vue app from webpack? Can you only do it using vue-cli-service build and therefore limited to vue only? I tried modifying my vue.config.js using the info found at https://cli.vuejs.org/guide/webpack.html & https://cli.vuejs.org/config/, but frankly I feel I am out of my depth at this point and unsure if what I am doing is even a good idea.
Is there a better strategy to take to get to my end goal? If this is a workable solution, what do I need to change about my configs to get both the angularjs and the vue app to build properly?
I wasn't seeing the wood for the trees. The problem isn't that that webpack.config.js doesn't succesfully producing a working angular & vue combined app, the problem is that I'm not providing a template that actually uses either of these things, so it just produces a blank index.html with the scripts provided but no content in the body.
Changing the
new HtmlWebpackPlugin({
//template: 'source/index.html',
}),
in my question to have a template that uses both an AnularJS component and a Vue component worked fine.

Adding Flow type checking to Webpack, Babel & Eslint

I have a Webpack 4 config file that compiles ES6 React code to ES5 using Babel (plus stage 3 preset and some optimisation plugins). It lints the code with Eslint.
import path from 'path';
export default {
mode: 'development',
entry: './app/app.jsx',
devtool: 'inline-source-map',
output: {
path: path.resolve(__dirname, 'dist'),
filename: 'app.js',
publicPath: '/dist/js',
},
module: {
rules: [
{
enforce: 'pre',
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'eslint-loader',
},
{
test: /\.(js|jsx)$/,
exclude: /node_modules/,
loader: 'babel-loader',
options: {
presets: ['es2015', 'stage-3', 'react'],
plugins: [
'babel-plugin-styled-components',
'transform-react-remove-prop-types',
'transform-react-inline-elements',
],
},
},
],
},
};
Now I want to add Flow type checking to my project but I can't find ANY good full examples of how a config setup like this should look.
I've tried adding eslint-plugin-flow to the Eslint config. I've tried adding babel-preset-flow to the Babel presets. I always end up getting errors either about needing an appropriate loader to handle the files, or it complains that my Flow code is invalid.
Note my config works before adding Flow. Can anyone show how to add Flow?

react-dom blowing out webpack bundle size MASSIVELY

This has got to be one of the strangest issues with webpack i have ever come across...
Check out this bundle breakdown:
react 116.01KB - fair enough
react-dom 533.24KB - seriously WTF
I thought it may be a corruption in my dependencies but nuking node_modules and reinstalling doesn't have any effect. I guess it's something to do with the way webpack is bundling it but i'm lost for ideas. The way i'm handing .js imports is pretty stock standard.
// webpack.config.js
const path = require('path');
// const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const Dashboard = require('webpack-dashboard');
const DashboardPlugin = require('webpack-dashboard/plugin');
const dashboard = new Dashboard();
module.exports = {
context: path.join(__dirname, 'src'),
entry: {
bundle: './index.js',
},
output: {
filename: 'bundle.js',
path: path.join(__dirname, 'build'),
},
module: {
rules: [
{
test: /\.html$/,
use: 'file-loader?name=[name].[ext]',
},
{
test: /.scss$/,
use: ExtractTextPlugin.extract({
fallback: 'style-loader',
use: [
'css-loader',
'postcss-loader',
],
}),
},
{
test: /\.js$/,
exclude: /node_modules/,
use: 'babel-loader',
},
],
},
plugins: [
// new BundleAnalyzerPlugin(),
new ExtractTextPlugin('styles.css'),
new DashboardPlugin(dashboard.setData),
],
devServer: {
quiet: true,
},
};
// .babelrc
{
"presets": [
"react",
"es2015"
],
"plugins": ["transform-object-rest-spread"]
}
http://elijahmanor.com/react-file-size/
In v15.4.0 the file size of react-dom grew from 1.17kB to 619.05kB. Which means my webpack setup isn't doing anything wrong bundling files. The reason why this module grew so large is because code was transferred from the react module.
I had to change my webpack.config.js, from
devtool: 'inline-source-map'
to
devtool: 'source-map'
Now it generates a much smaller .js + a separate .js.map file, for each of the chunks.
Notice the JS size is even less than react-dom.production.min.js in node_modules:
If you look into the corresponding folders under the node_modules folder, and note the file sizes, you'll see that there's nothing to be surprised about:
That is, the size of the bundle grows noticeably because the size of react-dom.js is large.
Add this following commands at plugins to minify your imports:
new webpack.optimize.OccurrenceOrderPlugin(),
new webpack.DefinePlugin(GLOBALS),
new webpack.optimize.UglifyJsPlugin(),
You should create a file or option to production bundle to use this plugins

Multiple package.jsons with ES6 Babel

I have a large project that I would like to divide up into multiple package.json's so that the dependencies for each part can be clearly stated and so those packages can be exported as individual parts.
However, I want my app to include each of these packages and compile them using webpack and babel. There are shared dependencies for the packages, so I don't want to just output each one to a /dist folder.
My ideal directory structure looks like this:
\main
\app
\node_modules
package.json
\package1
package.json
node_modules
index.js
\package2
package.json
node_modules
index.js
I tried multiple approaches:
Using webpack's resolve modules with something like path.resolve('app'). This just doesn't work, even though it should in theory.
Using main's package.json to reference others using "package1" : "file:../package1". This doesn't treat package1 as es6 javascript and throws errors. Using resolveLoaders in the webpack configuration does not help.
The webpack config I have is as follows.
module: {
loaders: [
{
test: /\.js?/,
loader: 'babel-loader',
include: [
path.resolve('app'),
path.resolve('../prose'),
],
query: {
plugins: [
['react-transform', {
transforms: [{
transform: 'react-transform-hmr',
// If you use React Native, pass 'react-native' instead:
imports: ['react'],
// This is important for Webpack HMR:
locals: ['module']
}]
}],
['transform-object-assign']
]
}
},
{ test: /\.css$/, loader: 'style-loader!css-loader!sass-loader' },
{ test: /\.svg$/, loader: 'file-loader' },
{ test: /\.png$/, loader: 'file-loader' },
{ test: /\.jpg$/, loader: 'file-loader' },
{ test: /\.json$/, loader: 'json-loader' }
]
},
resolve: {
modules: [
path.resolve('app'),
'node_modules',
],
extensions: ['.json', '.js', '.jsx'],
}
Any thoughts or examples of other projects that do this would be appreciated!
You should check out lerna. It enables you to use multiple package.jsons and even packages in one repo. It might help you with you requirements.

optimize image inside desired folder

I am using webpack for bundling. I am using reactjs and django. I want the static files used by Django and reactjs be separate. I could minified image but the minified images are saved to the folder where the output file is bundled. I want all the minified images to be saved inside frontend -> assets folder. How can i do it so?
The project structure looks like following
app - its a directory where static files are kept for Django. Webpack bundles the react files to app.js and is placed over here because Django template need it to render in its template as <script src='app/bundle/js/app.js'></script>.
frontend - It's a directory where all the react files reside. I want the images to be inside this directory(assets/images/). Images that will be used in reactjs.
How can i do it so?
my webpack right now is configured this way
const path = require("path");
if(!process.env.NODE_ENV) {
process.env.NODE_ENV = 'development';
}
module.exports = {
entry: [
'./src/index.js'
],
output: {
path: path.join("../app/static/build/", "js"),
filename: "app.js",
publicPath: "../app/static/build/"
},
devtoo: 'source-map',
debug: true,
module: {
loaders: [{
exclude: /node_modules/,
loader: 'babel',
query: {
presets: ['react', 'es2015', 'stage-1']
}
},
{test: /\.(jpe?g|png|gif|svg)$/i, loader: "file-loader?name=images/[name].[ext]"},
]
},
resolve: {
extensions: ['', '.js', '.jsx']
},
devServer: {
historyApiFallback: true,
contentBase: './'
}
};
You can specify custom output and public paths by using the outputPath and publicPath query name parameters:
loader: "file-loader?name=[name].[ext]&publicPath=assets/foo/&outputPath=app/images/"
But this feature isn't published to NPM yet. So unfortunatly you'll need to wait while it be published or clone and use this loader from github repo

Categories