@RudMa

Как настроить вывод скрипта в определенном месте при помощи Webpackе?

Всем привет! Необходимо настроить вывод скрипта прямо на странице, наподобие карт, для дальнейшего взаимодействия с бэком. На странице это должно выглядеть следующим образом:
<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>

Но в консоли возникает ошибка:
Cannot use import statement outside a module


Я попыталась настроить вывод importов в отдельном скрипте, но webpack подключает его в конце страницы. И естественно в консоли ошибка:

createApp is not defined


Как мне сделать при помощи webpack вывод скрипта в определенное место: Что-то типо такого:

<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>

Возможно ли вообще это сделать в webpack?
Это моя сборка
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({})
  //     ]
  //   }
});
  • Вопрос задан
  • 44 просмотра
Решения вопроса 1
GlazOtca
@GlazOtca
Если вы хотите, чтобы вебпак выводил подключаемый бандл со скриптами не в конец документа, а в определенное место, то нужно:
1 вырубить автоподключение в HTMLWebpackPlugin (inject: false). В моем примере было так:
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. в том месте шаблона страницы где хотите подключить бандл вставьте это:
<%= htmlWebpackPlugin.tags.bodyTags %>
Ну и если подключаете к странице скрипты с импортами не забывайте указывать
<script type="module">
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 2
@qwazimord
Интроверт
Учите синтаксис Модули, введение
<script type="module">
Ответ написан
Aetae
@Aetae
Тлен
webpack собирает js в замкнутый бандл. Он не пишет ничего в глобальную область видимости. Ты не можешь использовать ничего из cart.js если сам не "пошарил" это для общего доступа.
Правильным решением будет положить ВЕСЬ код в cart.js, в т.ч. и createApp и разве что передавать туда настройки тем или иным образом.
Но если очень хочется, в crat.js можно пошарить глобально нужные тебе функции, например:
window.createApp = createApp;
window.store = store;

Тогда второй вариант твоего кода заработает.
Скорее всего.)
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы