We have a Vue 2.7 SPA at my workplace.
Nobody ever configured a dev build for it, nobody ever used a debugger (it’s a docker-compose environment).
I’m currently implementing the dev build, and so far it’s been a success, except for the fact that I cannot access variables inside a debugger.
Source maps seem to work, since I can successfully place breakpoints inside .vue
component files.
I start the dev server by:
npm run start -- --port 8000 --host 0.0.0.0
(it’s inside a docker-compose
network, so don’t mind the 0.0.0.0
bit)
The package.json
file looks like this:
{
"name": "...",
"version": "1.0.0",
"description": "",
"scripts": {
"start": "webpack-dev-server --open --history-api-fallback",
"build": "webpack --mode production",
"webpack": "webpack --mode=development --watch"
},
"browserslist": [
"> 0.25%, not dead"
],
"dependencies": {
"autoprefixer": "^10.4.11",
"axios": "^0.27.2",
"bootstrap": "^4.6.1",
"bootstrap-vue": "^2.21.2",
"inputmask-core": "^2.2.0",
"mini-toastr": "^0.8.1",
"moment": "^2.29.4",
"postcss-preset-env": "^7.8.2",
"qs": "^6.11.0",
"v-mask": "^2.3.0",
"vue": "^2.6.12",
"vue-i18n": "^8.27.2",
"vue-notification": "^1.3.20",
"vue-notifications": "^0.9.0",
"vue-resource": "^1.5.1",
"vue-router": "^3.4.9",
"vue2-datepicker": "^3.11.0",
"vuetable-2": "^1.7.5",
"vuex": "^3.6.2"
},
"devDependencies": {
"@babel/core": "^7.12.10",
"@babel/preset-env": "^7.19.1",
"@prerenderer/renderer-jsdom": "^0.2.0",
"babel-loader": "^8.2.2",
"clean-webpack-plugin": "^4.0.0",
"copy-webpack-plugin": "^6.0.3",
"core-js": "^3.25.3",
"css-loader": "^3.6.0",
"del-cli": "^3.0.1",
"eslint": "^8.25.0",
"eslint-plugin-vue": "^9.6.0",
"file-loader": "^6.2.0",
"html-webpack-plugin": "^4.5.1",
"mini-css-extract-plugin": "^0.9.0",
"optimize-css-assets-webpack-plugin": "^5.0.3",
"postcss": "^8.4.16",
"postcss-loader": "^4.3.0",
"prerender-spa-plugin": "^3.4.0",
"sass": "^1.56.1",
"sass-loader": "^10.2.0",
"style-loader": "^2.0.0",
"svg-sprite-loader": "^6.0.11",
"svgo-loader": "^3.0.1",
"terser-webpack-plugin": "^3.0.6",
"vue-loader": "^15.9.6",
"vue-style-loader": "^4.1.2",
"vue-template-compiler": "^2.6.12",
"webpack": "^4.46.0",
"webpack-cli": "^3.3.12",
"webpack-dev-server": "^3.11.0",
"webpack-fix-style-only-entries": "^0.5.1"
}
}
Finally, the webpack.config.js
looks like this:
const webpack = require('webpack');
const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
const { VueLoaderPlugin } = require('vue-loader')
const FixStyleOnlyEntriesPlugin = require("webpack-fix-style-only-entries")
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const OptimizeCssAssetsPlugin = require('optimize-css-assets-webpack-plugin')
const TerserPlugin = require('terser-webpack-plugin')
const SpriteLoaderPlugin = require('svg-sprite-loader/plugin');
const CopyPlugin = require('copy-webpack-plugin')
const HtmlWebpackPlugin = require('html-webpack-plugin')
module.exports = {
devtool: 'source-map',
devServer: {
allowedHosts: ["all"],
disableHostCheck: true,
},
entry: {
app: path.resolve(__dirname, 'src/index.js'),
},
output: {
filename: '[name].[hash].js',
chunkFilename: '[name].[hash].bundle.js',
path: path.resolve(__dirname, 'dist'),
publicPath: '/',
},
module: {
rules: [
{
test: /.vue$/,
loader: 'vue-loader',
options: {
loaders: {
css: 'vue-style-loader!css-loader!sass-loader', // <style lang="css">
scss: 'vue-style-loader!css-loader!sass-loader', // <style lang="scss">
sass: 'vue-style-loader!css-loader!sass-loader?indentedSyntax' // <style lang="sass">
}
}
},
{
test: /.svg$/,
include: path.resolve(__dirname, 'src/assets/icons'),
use: [
{
loader: 'svg-sprite-loader',
options: {
extract: true,
publicPath: '/assets/icons/',
spriteFilename: svgPath => `sprite${svgPath.substr(-4)}`
}
},
// 'svg-sprite-loader',
{
loader: 'svgo-loader',
options: {
plugins: [
{
name: 'removeAttributesBySelector',
params: {
selector: "[stroke='#787F9B']",
attributes: "stroke"
}
},
{
name: 'removeAttributesBySelector',
params: {
selector: "[fill='#787F9B']",
attributes: "fill"
}
},
{
name: 'removeAttributesBySelector',
params: {
selector: "[stroke='#B2BAD8']",
attributes: 'stroke'
}
},
{
name: 'removeAttributesBySelector',
params: {
selector: "[fill='#B2BAD8']",
attributes: 'fill'
}
},
{
name: 'removeAttributesBySelector',
params: {
selector: "[fill='none']",
attributes: "fill"
}
},
]
}
}
]
},
{
test: /.m?js$/,
exclude: /node_modules/,
use: {
loader: 'babel-loader',
options: {
presets: [
[
"@babel/preset-env",
{
"debug": true,
"useBuiltIns": "entry",
"corejs": "3.22"
}
]
],
}
},
},
{
test: /.(png|jpe?g|gif|ico)$/i,
loader: 'file-loader',
options: {
name: 'assets/img/[name].[ext]',
},
},
{
test: /.(ttf|woff|woff2|eot)$/,
loader: 'file-loader',
options: {
name: '[name].[ext]?[hash]'
}
},
{
test: /.(sass|scss)$/,
// include: path.resolve(__dirname, 'src/assets/scss'),
exclude: /node_modules/,
use: [
{
loader: MiniCssExtractPlugin.loader,
},
{
loader: 'css-loader',
options: {
url: false,
},
},
{
loader: 'sass-loader',
options: {
additionalData: "@import '@/assets/scss/colors.scss';"
},
},
],
},
{
test: /.css$/,
use: [
'vue-style-loader',
MiniCssExtractPlugin.loader,
'css-loader',
'postcss-loader'
]
}
],
},
optimization: {
splitChunks: {
chunks: 'all',
cacheGroups: {
vendor: {
test: /[\/](node_modules)[\/].+.js$/,
name: 'vendor',
}
}
},
minimizer: [
new OptimizeCssAssetsPlugin({
cssProcessorOptions: { map: { inline: false, }, },
cssProcessorPluginOptions: {
preset: [
'default',
{ discardComments: { removeAll: true } },
],
},
}),
new TerserPlugin({
extractComments: false,
terserOptions: {
output: {
comments: false,
},
},
}),
],
},
resolve: {
symlinks: false,
modules: [path.resolve(__dirname, 'node_modules')],
alias: {
'@': path.resolve(__dirname, 'src'),
layouts: path.resolve(__dirname, 'src/layouts'),
utils: path.resolve(__dirname, 'src/utils'),
routes: path.resolve(__dirname, 'src/routes'),
assets: path.resolve(__dirname, 'src/assets'),
vue$: 'vue/dist/vue.runtime.min.js'
// 'vue-resource': 'vue-resource/dist/vue-resource.esm.js'
},
extensions: ['.js', '.vue', '.json', '.png']
},
plugins: [
new webpack.DefinePlugin({
'API_URL': `'${process.env.API_URL || ""}'`,
'WS_URL': `'${process.env.WS_URL || ""}'`,
}),
new CleanWebpackPlugin(),
new CopyPlugin({
patterns: [
{ from: './src/robots.txt', to: './assets/robots.txt' },
path.resolve(__dirname, 'src/assets/img/favicon.ico'),
],
}),
require('autoprefixer'),
new SpriteLoaderPlugin({
plainSprite: true,
}),
new VueLoaderPlugin(),
new FixStyleOnlyEntriesPlugin(),
new MiniCssExtractPlugin({
filename: './assets/css/[name].[hash].bundle.css',
}),
new HtmlWebpackPlugin({
// MANIFEST_FILENAME: '/assets/manifest.json',
template: 'src/index.html',
title: '...',
favicon: 'src/assets/img/favicon.ico',
// inject: false,
// scripts: [`/app.js?v=${new Date().getTime()}`]
meta: [{
name: 'viewport',
content: 'width=device-width, initial-scale=1.0'
}]
// links: [
// "https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.css",
// {rel: "shortcut icon", href: "/assets/icons/favicon.ico", type: "image/x-icon"},
// ]
}),
],
};
It’s the last frontier of the dev environment, which I haven’t yet been able to conquer.
I understand the problem: arguments / variables get mangled during the minification process. Here is component’s method, which I was trying to debug:
async onAddUsdtTrc20Wallet() {
try {
const response = await this.createNewCryptoWallet('USDT-TRC20X');
const address = response.wallet_address;
this.showSuccess(this.$t('profilePage.wallets.successAddUsdtTrc20Wallet') + address);
} catch (err) {
this.showError(this.$t('profilePage.wallets.errorAddUsdtTrc20Wallet') + err.toString());
}
}
After minification it looks like this:
onAddUsdtTrc20Wallet: function onAddUsdtTrc20Wallet() {
var _this7 = this;
return _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime().mark(function _callee2() {
var response, address;
return _regeneratorRuntime().wrap(function _callee2$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
_context2.prev = 0;
_context2.next = 3;
return _this7.createNewCryptoWallet('USDT-TRC20X');
case 3:
response = _context2.sent;
address = response.wallet_address;
_this7.showSuccess(_this7.$t('profilePage.wallets.successAddUsdtTrc20Wallet') + address);
_context2.next = 11;
break;
case 8:
_context2.prev = 8;
_context2.t0 = _context2["catch"](0);
_this7.showError(_this7.$t('profilePage.wallets.errorAddUsdtTrc20Wallet') + _context2.t0.toString());
case 11:
case "end":
return _context2.stop();
}
}
}, _callee2, null, [[0, 8]]);
}))();
}
What I tried:
- I tried using
"devtool": "eval-source-map"
. - Tried removing
"minimizer"
and setting"minify"
field inside"optimization"
tofalse
. - Tried setting
TerserPlugin
options to{minify: TerserPlugin.esbuildMinify, terserOptions: { minify: false, minifyWhitespace: true, minifyIdentifiers: false, minifySyntax: true,}
- Tried removing
optimization
altogether.
None of these steps changed the generated app.js
output script. Double checked by exec -it
ing inside the container to make sure new webpack.config.js
was in place.
Anybody had this kind of problem?
7