I'm trying to compose a webpack bundle from existing js files and use exports from that in both other JS files and occasionally in html script tag. Later add babel to transpile the whole thing to es5, hence commented out section with babel and ts, that btw works fine.
For now I am having a problem with the exports using straight webpack.
Webpack config as as follows:
var path = require('path');
const { updateCommaList } = require('typescript');
module.exports = {
entry: {
'core' : [
'./src/utils.js',
'./src/zdlg.js'
]
},
devtool: 'source-map',
stats: 'verbose',
resolve: {
modules: ['node_modules']
},
resolveLoader: {
extensions: ['.ts', '.tsx'],
mainFields: ['loader', 'main']
},
output: {
filename: '[name].js',
library: "LIB",
libraryTarget: 'var',
path: path.resolve(__dirname, "dist")
},
module: {
}
};
I can bundle files, no errors there. I'm exporting functions using export statement like so:
export function v ...
And in the html file I have
<script src="./core.js"></script>
<script type="module" src="./io.js"></script>
After tinkering for last few days I've figured out couple things.
If I have a single file in the entry section for core object, exports work, in that the LIB variable has property for each exported function and I can call LIB.v() fine.
imports do not work anyway, i.e.
io.js import:
import {v} from './core.js';
Generates an error when loading the page: Uncaught SyntaxError: import not found: v for the line above.
Adding second file to entry causes webpack to override exports from the 1st file. The reason I didn't see any exports initially was that zdlg.js wasn't exporting anything, and LIB had no exports. If zdlg.js exports any functions they are the only ones that show up on the LIB.
So, in the end, I can export functions from a single file, but I thought the whole purpose of the webpack was to allow to compose modules from multiple files.
I'm not sure what am I missing or where I am going wrong, should be very basic stuff...
In case it is important, here's dev dep list too:
"devDependencies": {
"#babel/core": "^7.8.7",
"#babel/preset-env": "^7.8.7",
"babel-loader": "^8.0.6",
"install": "^0.13.0",
"npm": "^6.14.7",
"ts-loader": "^6.2.1",
"typescript": "^3.8.3",
"webpack": "^4.43.0",
"webpack-cli": "^3.3.12",
"webpack-dev-middleware": "^3.7.2",
"webpack-dev-server": "^3.11.0",
"webpack-merge": "^5.0.9"
}
Made it work, although not sure if this is the best way.
Basically, instead of adding multiple entries in the export's entry section, I've created index.js file which reexported all the exports from the files I needed:
require('./src/ut');
require('./src/zd');
export * from './src/ut';
export * from './src/zd'
Entry is now just index.js
entry: {
'core' : 'index.js'
},
Works as intended, but I am not sure why wouldn't webpack automate this, and why would I have to export everything myself...
Related
I'm building a website in Wordpress and I am trying to use gulp, webpack-stream, and babel-loader to convert JSX to JS (I was successful at using gulp to sass my CSS, so I removed that code).
Whenever I run the gulp command in terminal to convert the JSX, I get this incorrect output in the generated Javascript file:
!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){"use strict";n.r(t);n(1);console.log("ugh")},function(e,t){console.log("test running")}]);
I can't figure out if I'm getting this error because I'm missing vital packages or if something else is wrong with my gulp commands.
Here is my package.json's dependencies
{
"devDependencies": {
"#babel/core": "^7.11.4",
"#babel/preset-env": "^7.11.0",
"#babel/register": "^7.10.5",
"#wordpress/browserslist-config": "^2.7.0",
"autoprefixer": "^9.8.6",
"babel-loader": "^8.1.0",
"babelify": "^10.0.0",
"browserify": "^17.0.0",
"browserslist": "^4.14.0",
"gulp": "^4.0.2",
"gulp-concat": "^2.6.1",
"gulp-postcss": "^8.0.0",
"gulp-sass": "^4.1.0",
"gulp-sourcemaps": "^2.6.5",
"gulp-terser": "^1.4.0",
"webpack-stream": "^6.1.0"
},
"browserslist": [
"extends #wordpress/browserslist-config"
]
}
Here is my gulpfile.babel.js file:
// load gulp
import gulp from 'gulp';
// utility
import sourcemaps from 'gulp-sourcemaps';
// css-related
import sass from 'gulp-sass';
import postcss from 'gulp-postcss';
import autoprefixer from 'autoprefixer';
// js-related
import webpack from 'webpack-stream';
// project
const paths = {
scripts: {
src: 'src/scripts/bundle.js',
dest: './build/js/'
}
}
// enable javasript
export const scripts = (done) => {
return gulp.src( paths.scripts.src )
.pipe( webpack({
// module: {
// rules: [
// {
// test: /\.js$/,
// use: {
// loader: 'babel-loader',
// options: {
// presets: ['#babel/preset-env']
// }
// }
// }
// ]
// },
output: {
filename: 'bundle.js'
}
}) )
.pipe( gulp.dest( paths.scripts.dest ) );
done();
}
I commented out the webpack module items because I was eliminating the possible reasons for why it wasn't working. When I commented out webpack, the code "worked" in that it copied the file over to the build folder.
Here is the bundle.js file that contains JSX
console.log('ugh');
import './components/test';
let x = 0;
and here is what test.js contains
console.log("test running");
I also received the following message inside terminal:
(node:13196) [DEP0097] DeprecationWarning: Using a domain property in MakeCallback is deprecated. Use the async_context variant of MakeCallback or the AsyncResource class instead.
[22:53:54] Version: webpack 4.44.2
Built at: 10/20/2020 10:53:54 PM
Asset Size Chunks Chunk Names
bundle.js 1020 bytes 0 [emitted] main
Entrypoint main = bundle.js
WARNING in configuration
The 'mode' option has not been set, webpack will fallback to 'production' for this value. Set 'mode' option to 'development' or 'production' to enable defaults for each environment.
You can also set it to 'none' to disable any default behavior. Learn more: https://webpack.js.org/configuration/mode/
[22:53:54] Finished 'scripts' after 1.69 s
I'm totally new to using node, npm, and gulp, and have been following tutorials as best I can to try to get this to work, but every tutorial is either old, or I end up with garbage code in the destination file. I'm also the lone developer and designer, and I desperately need some feedback/assistance. I would be forever grateful to whoever can help me get this to work properly, and am happy to provide any additional information in order to figure this out.
I'm building a vue cli 3 app with vue-cli-plugin-compression and vue-cli-plugin-prerender-spa installed. (Under the hood these use prerender-spa-plugin and compression-webpack-plugin).
The prerender-spa-plugin renames index.html to app.html. It then prerenders app.html and stores the resulting html in a new index.html. The page is prerendered correctly and app.html is correctly gzipped. However, the resulting index.html (the page that is the result of the prerendering) is not gzipped. How can I get the result of the prerender to be gzipped as well?
Here's my vue.config.js:
module.exports = {
devServer: {
port: 3000
},
configureWebpack: {
devtool: 'source-map'
},
pluginOptions: {
prerenderSpa: {
customRendererConfig: {
injectProperty: '__PRERENDER_INJECTED',
inject: {},
},
registry: undefined,
renderRoutes: [
'/'
],
useRenderEvent: true,
headless: true,
onlyProduction: true,
postProcess: route => {
// Defer scripts and tell Vue it's been server rendered to trigger hydration
route.html = route.html
.replace(/<script (.*?)>/g, '<script $1 defer>')
.replace('id="app"', 'id="app" data-server-rendered="true"');
return route;
}
},
compression:{
gzip: {
filename: '[path].gz[query]',
algorithm: 'gzip',
test: /\.(js|js\.map|css|html)$/,
minRatio: 0.8,
}
}
}
};
I tried to prerender before compression, but it doesn't change anything:
chainWebpack: (config) => {
config.plugin('pre-render').before('gzip-compression');
config.plugin('gzip-compression').after('html');
},
So, it turns out that the prerender-spa-plugin is outdated and only works for webpack 4, most of the issues have been overcome in webpack 5 with new hooks
So I refactored the code base of prerender-spa-plugin to work for webpack 5 (and only for it), I also had to remove some features like the html minification as now other compression plugins will correctly run on the html
You can find the package on npm prerender-spa-plugin-next
You will need to update your vue cli plugins to the version ^5 to use webpack 5
As of writing:
"#vue/cli-plugin-babel": "^5.0.4",
"#vue/cli-plugin-eslint": "^5.0.4",
"#vue/cli-plugin-router": "^5.0.4",
"#vue/cli-service": "^5.0.4",
"compression-webpack-plugin": "^6.1.1",
"html-webpack-plugin": "^5.3.1",
...
Make sure all of your other dependencies are also updated (Eslint and all the webpack plugins and loaders)
This might turn into a lot of trial and error to get it to compile after a big update but the trouble is worth it
Let me know if you have any question regarding the usage of my package
There's dozens and dozens of questions like this one, and none have helped because the root cause is always something I'm not doing. I'm making a bundle for the browser with webpack 4.26.1, and I keep getting Uncaught ReferenceError: require is not defined when I open the webapp in the browser no matter what I do.
I'm not using target: 'node'.
I'm not requiring webpack-node-externals.
I'm not explicitly excluding anything from the bundle.
I'm not using noParse.
I even tried explicitly setting target: 'web' even though it's the default just to see if anything somehow changed.
This is the entirety of my webpack.config.json:
const path = require('path');
module.exports = {
mode: 'production',
entry: './src/main/webapp/resources/app/template.core.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'src/main/webapp/resources/dist')
}
};
This is my package.json
{
(...)
"main": "src/main/webapp/template.core.js",
"dependencies": {
"angular": "^1.6.10",
"angular-animate": "^1.6.10",
"angular-route": "^1.6.10",
"angular-sanitize": "^1.6.10",
"angular-upload": "^1.0.13",
"ui-select": "^0.19.8",
"angular-ui-bootstrap": "^2.5.0",
"moment": "2.22.2"
},
"devDependencies": {
"npm": "^5.6.0",
"webpack": "^4.26.1",
"webpack-cli": "^3.1.2",
"jshint": "^2.9.6"
},
"scripts": {
"lint": "jshint src/main/webapp --exclude src/main/webapp/resources/static,src/main/webapp/resources/dist",
"build": "webpack"
},
(...)
}
What am I doing wrong?
For future reference, my issue was something as basic as having the wrong <script> includes in the html, because due to my webpack configurations, the bundles' filenames are different for development and production modes. I am now using html-webpack-plugin to generate the includes, with my template file being an empty file with just a comment so it outputs nothing but the script tags themselves. Here's how it looks in my webpack.config.js:
var HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
...
plugins: [
new HtmlWebpackPlugin({
template: 'path/to/empty/template',
filename: 'path/to/templated/output'
})
],
...
};
index.js:
import foo from "./foo.js"; // works fine
import blah from "./blah.js"; // works fine
import css from "style-loader!css-loader!../content/site.css"; // fails with exception
I am using Webpack 4.20.x. When I use the ES6 module import statement to import and bundle a CSS file, I get an exception in the console (see below) and my CSS does not load on the page.
Exception:
Failed to resolve module specifier
"style-loader!css-loader!../content/site.css". Relative references
must start with either "/", "./", or "../".
I've got the loaders instsalled as dev dependencies.
Excerpt from package.json:
"devDependencies": {
"css-loader": "^1.0.0",
"lite-server": "^2.4.0",
"style-loader": "^0.23.1",
"webpack": "^4.20.2",
"webpack-cli": "^3.1.2"
}
I know I can configure the loaders in my webpack.config.json but I want to, just for practice, configure them inline.
I know I could use the CommonJS style webpack-require() syntax also for the inline import in place of ES 6 module style import, but I want to the import first.
I am basically trying each and every syntax one by one.
EDIT
In response to the commenter #axm__, I was asking webpack to bundle my files. Here is what my webpack.config.js looked like at that time. I wasn't using configuration based loaders at the time.
const path = require("path");
// How to use source maps, css, sass
module.exports = {
mode: "production",
entry: {
index: path.resolve(__dirname, "scripts/index.js"),
contact: path.resolve(__dirname, "scripts/contact.js"),
about: path.resolve(__dirname, "scripts/about.js")
},
output: {
filename: "[name].js",
path: path.resolve(__dirname, "dist")
},
/* module: {
rules: [
{
test: /\.css/,
use: [
{ loader: "style-loader" },
{
loader: "css-loader",
options: {
modules: true
}
}
]
}
]
} */
};
I am leaning webpack. However, here comes a bug that "You may need an appropriate loader to handle this file type.", I have checked the webpack.config.js, it is correct.
const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const webpack = require("webpack");
module.exports = {
entry: {
app: './src/main.js',
print: './src/print.js'
},
devtool: 'inline-source-map',
devServer: {
contentBase: 'dist',
hot: true,
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist')
},
module: {
rules: [{
test: /\.css$/,
use: [
'style-loader',
'css-loader'
]
}]
},
plugins: [
new CleanWebpackPlugin(['dist']),
new HtmlWebpackPlugin({
title: 'Output Management'
}),
new webpack.HotModuleReplacementPlugin()
]
};
Additionally, here is my js file and css file:
import './style.css';
body {
background-color: blue;
}
And the console log this:
./src/style.css
Module parse failed: D:\FrontEndWorkSpace\webpack-demo\src\style.css Unexpected token (1:5)
You may need an appropriate loader to handle this file type.
| body {
| background-color: blue;
| }
Additional, I have already installed both style-loader and css-loader, here are my dependencies on my package.json:
"devDependencies": {
"clean-webpack-plugin": "^0.1.16",
"css-loader": "^0.28.4",
"csv-loader": "^2.1.1",
"file-loader": "^0.11.2",
"html-webpack-plugin": "^2.29.0",
"style-loader": "^0.18.2",
"webpack": "^3.4.1",
"webpack-dev-server": "^2.6.1",
"xml-loader": "^1.2.1"
}
EDIT: For some unknown reasons, it's works.
Make sure you have installed the loaders you're trying to use from NPM. You should see them in both your package.json file and in your node_modules folder of the project. If you don't see them, you can install them and save them to your dev dependencies in your terminal:
$ npm install style-loader css-loader --save-dev
Last bit, I've found this YouTube video series extremely helpful in getting started with Webpack 2. It's changed a lot in its first couple of years, so relevant references are tricky to separate from the obsolete ones.
Good luck taming the webpack beast!
EDIT: Removed extra stuff.