R
R
RudMa2021-10-20 08:08:23
webpack
RudMa, 2021-10-20 08:08:23

How to customize script output in a specific location using Webpack?

Hello! It is necessary to configure the output of the script directly on the page, like maps, for further interaction with the back. On the page it should look like this:

<div class="content__main">
  <div class="cells">
    <div class="cell cell-xl-8">
      <div id="app-cart">
        <script>
          import { createApp } from "vue";
          import App from "./App.vue";
          import store from "./vuex/store.js";

          let cartApp = document.querySelector("#app-cart");


          if (cartApp) {
            createApp(App, { URL: "http://localhost:3000/products" })
              .use(store)
              .mount("#app-cart");
          }
        </script>
      </div>
    </div>

But an error occurs in the console:
Cannot use import statement outside a module


I tried to set up the output of imports in a separate script, but webpack includes it at the end of the page. And of course in the console error:

createApp is not defined


How do I make the script output to a specific location using webpack: Something like this:

<div class="cell cell-xl-8">
  <div id="app-cart">
    <script src="assets/js/cart.js"></script>
    <script>
      let cartApp = document.querySelector("#app-cart");
      if (cartApp) {
        createApp(App, { URL: "http://localhost:3000/products" })
          .use(store)
          .mount("#app-cart");
      }
    </script>
  </div>
</div>

Is it even possible to do this in webpack?
This is my build
const webpack = require("webpack");
const path = require("path");
const fs = require("fs");
const {
  CleanWebpackPlugin
} = require("clean-webpack-plugin");
const HtmlWebpackPlugin = require("html-webpack-plugin");
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const CopyPlugin = require("copy-webpack-plugin");
const {
  VueLoaderPlugin
} = require('vue-loader');
// const CompressionPlugin = require('compression-webpack-plugin');
// const UglifyJsPlugin = require("uglifyjs-webpack-plugin");
// const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const ImageminPlugin = require("imagemin-webpack-plugin").default;

const pages = fs
  .readdirSync(path.resolve(__dirname, "src/templates/pages"))
  .filter((fileName) => fileName.endsWith(".pug"));

module.exports = (env, options) => ({
  entry: {
    main: "./src/index.js",
    theming: "./src/js/theming.js",
    cart: "./src/cart-vue/cart-vue.js"
  },
  output: {
    publicPath: "",
    path: path.resolve(__dirname, "dist"),
    filename: "assets/js/[name].js"
  },
  devtool: "source-map",
  // devServer: {
  //   static: "./dev",
  //   port: 3000
  // },
  module: {
    rules: [
      {
        test: /\.pug$/,
        include: path.resolve(__dirname, "src/templates"),
        use: [
          {
            loader: "pug-loader",
            options: {
              pretty: true
            }
          }
        ]
      },
      {
        test: /\.(scss|css)$/,
        include: path.resolve(__dirname, "src/sass"),
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              publicPath: "../../"
            }
          },
          {
            loader: "css-loader"
          },
          {
            loader: "postcss-loader"
          },
          {
            loader: "resolve-url-loader"
          },
          {
            loader: "sass-loader",
            options: {
              sourceMap: true,
              sassOptions: {
                outputStyle: "expanded"
              }
            }
          }
        ]
      },
      {
        test: /\.(png|jpe?g|gif|svg)$/i,
        include: /theme-images/,
        type: "asset/resource",
        generator: {
          filename: "assets/images/[name][ext]"
        }
      },
      {
        test: /\.(png|jpe?g|gif|svg)$/i,
        include: /content-images/,
        type: "asset/resource",
        generator: {
          filename: "assets/content-images/[name][ext]"
        }
      },
      {
        test: /\.(woff|woff2|eot|ttf|otf)$/i,
        type: "asset/resource",
        generator: {
          filename: "assets/fonts/[name][ext]"
        }
      },
      {
        test: /\.vue$/,
        include: path.resolve(__dirname, "src/cart-vue"),
        loader: "vue-loader"
      },
      {
        test: /\.js$/,
        exclude: /(node_modules|bower_components|vendor)/,
        include: path.resolve(__dirname, "src"),
        use: {
          loader: "babel-loader",
          options: {
            presets: ["@babel/preset-env"]
          }
        }
      }
    ]
  },
  plugins: [
    options.mode === "development" ? false : new CleanWebpackPlugin(),
    // new CleanWebpackPlugin(),
    new MiniCssExtractPlugin({
      filename: "assets/css/[name].css"
    }),
    new VueLoaderPlugin(),
    ...pages.map(
      page =>
        new HtmlWebpackPlugin({
          template: "./src/templates/pages/" + page,
          chunks: ["main", "theming"],
          filename: page.replace(/\.pug/, ".html"),
          minify: false
        })
    ),
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "./src/templates/pages/cart-vue.pug"),
      chunks: ["main", "theming", "cart"],
      filename: "cart-vue.html",
      minify: false
    }),
    // new webpack.ProvidePlugin({
    //   // $: "jquery",
    //   // jQuery: "jquery",
    //   // "window.jQuery": "jquery",
    // }),
    new ImageminPlugin({
      bail: false, // Ignore errors on corrupted images
      cache: true,
      imageminOptions: {
        pngquant: {
          quality: "95-100"
        }
      }
    }),
    new CopyPlugin({
      patterns: [
        {
          from: "src/js/vendor/*.js",
          to: "assets/js/vendor/[name].js"
        },
        {
          from: "src/sass/vendor/*.css",
          to: "assets/css/vendor/[name].css"
        },
        {
          from: "src/images/content-images/*.jpg",
          to: "assets/content-images/[name].jpg"
        }
      ]
    })
  ].filter(n => n)
  //   optimization: {
  //     minimizer: [
  //         new UglifyJsPlugin({
  //             cache: true,
  //             parallel: true,
  //             sourceMap: false,
  //             extractComments: false
  //         }),
  //         new CompressionPlugin({
  //             test: /\.js$|\.css(\?.*)?$/i
  //         }),
  //         new OptimizeCSSAssetsPlugin({})
  //     ]
  //   }
});

Answer the question

In order to leave comments, you need to log in

3 answer(s)
G
GlazOtca, 2021-10-20
@RudMa

If you want webpack to output the plug-in bundle with scripts not to the end of the document, but to a certain place, then you need to:
1 disable auto-plugin in HTMLWebpackPlugin (inject: false). In my example it was like this:

plugins: [
        new HTMLWebpackPlugin({
            templateParameters: {
                'foo': 'bar'
            },
            template: './index.html',
            inject: false,
            meta: {
                charset: { charset: 'utf-8' },
                viewport: 'width=device-width, initial-scale=1'
            },
            minify: {
                removeComments: isProd,
                collapseWhitespace: isProd
            }
        }),
]

2. in the place of the page template where you want to connect the bundle, paste this:
<%= htmlWebpackPlugin.tags.bodyTags %>
Well, if you connect scripts with imports to the page, do not forget to specify
<script type="module">

Q
Quasimord Sidorovich, 2021-10-20
@qwazimord

Learn Syntax Modules Introduction
<script type="module">

A
Aetae, 2021-10-20
@Aetae

webpack collects js in a closed bundle. It does not write anything to the global scope. You can't use anything from cart.js unless you "rummage around" it for public access.
The correct solution would be to put ALL the code in cart.js, incl. and createApp and perhaps pass the settings there one way or another.
But if you really want to, in crat.js you can rummage around the functions you need globally, for example:

window.createApp = createApp;
window.store = store;

Then the second version of your code will work.
More likely.)

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question