Глобальная экспозиция компонентов Vue через Webpack
В общем, я пытаюсь создать гибридную структуру для проекта MVC. Инфраструктура внешнего интерфейса будет управляться Webpack и VueJS. Тем не менее, после нескольких недель работы и получения необходимых знаний Webpack вместе с Vue, я не смог добиться того, чего хочу.
Итак, прямо выше - структура проекта, а именно уровень веб-пакета. Папка webpack сначала будет упакована Webpack в папку wwwroot/dist, которая в итоге будет выглядеть следующим образом;
Отсюда мы сможем импортировать комплекты в основной макет представления MVC, который затем мы можем применить встроенным Vue к каждому представлению. Цель в том, чтобы сделать это так, что мы можем сначала,
- Пакетные стили и часто используемые библиотеки js с Webpack
- Иметь возможность использовать компоненты Vue и Vue, одновременно создавая структуру чанка (0.js, 1, 2 ....)
- Из-за 2 мы сможем склониться к CSR (Рендеринг на стороне клиента).
Вот мой webpack.config.js для справки.
const path = require('path');
const webpack = require('webpack');
const MergeIntoSingleFilePlugin = require('webpack-merge-and-include-globally');
const UglifyJsPlugin = require('uglifyjs-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const extractCSS = new ExtractTextPlugin('bundle.css');
// Declaring multiple modules
// https://stackru.com/questions/16631064/declare-multiple-module-exports-in-node-js
module.exports = function (env) {
env = env || {};
var isProd = env.NODE_ENV === 'production';
// Setup base config for all environments
var config = {
entry: {
main: './Webpack/js/main'
},
output: {
// The format for the outputted files
filename: '[name].js',
// Put the files in "wwwroot/js/"
path: path.resolve(__dirname, 'wwwroot/dist/')
},
devtool: 'eval-source-map',
resolve: {
alias: {
'vue': 'vue/dist/vue.esm.js' // Use the full build
},
extensions: ['.js', '.jsx']
},
plugins: [
extractCSS,
new webpack.ProvidePlugin({
$: "jquery",
jQuery: "jquery",
"window.jQuery": "jquery'",
"window.$": "jquery",
"dt": "datatables.net",
Popper: ['popper.js', 'default']
}),
new MergeIntoSingleFilePlugin({
files: {
// Table related libraries
"tbl.js": [
'node_modules/datatables.net/js/jquery.dataTables.js',
'node_modules/datatables.net-bs4/js/dataTables.bootstrap4.js'
],
"tbl.css": [
'node_modules/datatables.net-bs4/css/dataTables.bootstrap4.css',
'node_modules/datatables.net-buttons-bs4/css/buttons.bootstrap4.min.css'
],
"duo-web.js": [
'Webpack/js/securo/Duo-Web-v2.js'
]
}
})
],
module: {
rules: [
{ test: /\.css$/, use: extractCSS.extract(['css-loader?minimize']) },
{ test: /\.(png|jpg|jpeg|gif|svg)$/, use: 'url-loader?limit=25000' },
{ test: /\.(png|woff|woff2|eot|ttf|svg)(\?|$)/, use: 'url-loader?limit=100000' },
// Recognise VueJS
{
test: /\.vue$/,
loader: 'vue-loader'
},
// Expose jQuery globally
// https://stackru.com/questions/47469228/jquery-is-not-defined-using-webpack
{
test: require.resolve('jquery'),
use: [{
loader: 'expose-loader',
options: 'jQuery'
},{
loader: 'expose-loader',
options: '$'
}]
},
{
test: require.resolve('bootbox'),
use: [{
loader: 'expose-loader',
options: 'bootbox'
}]
},
{
test: require.resolve('clipboard'),
use: [{
loader: 'expose-loader',
options: 'Clipboard'
}]
},
],
loaders: [
{
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "url-loader"
},
{
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
loader: "url-loader"
},
{
test: /\.vue$/,
loader: 'vue-loader'
}
]
}
};
// Alter config for prod environment
if (isProd) {
config.devtool = 'source-map';
config.plugins = config.plugins.concat([
new UglifyJsPlugin({
sourceMap: true
}),
// https://vuejs.org/v2/guide/deployment.html
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"production"'
}
})
]);
}
return config;
};
function toObject(paths) {
var ret = {};
paths.forEach(function (path) {
ret[path.split('/').slice(-1)[0]] = path;
});
return ret;
}
А вот и main.js
// Load the css first
import 'bootstrap/dist/css/bootstrap.css';
import '../css/counter-ui.css';
import '../css/site.css';
import 'font-awesome/css/font-awesome.css';
// Then the js
import Vue from 'vue'; // Compile included builds https://github.com/nuxt/nuxt.js/issues/1142
import 'jquery';
import 'jquery-validation';
import 'jquery-validation-unobtrusive';
import 'popper.js';
import 'bootstrap';
import 'bootstrap-datepicker';
import 'bootbox';
import 'clipboard';
import 'magicsuggest';
import 'nouislider';
import '../js/counter-ui.js';
import 'formcache';
// Vue Components
Vue.component(/* webpackChunkName: "base-select" */ 'base-select', () => import('./components/base-select.vue'));
// Expose Vue globally
// https://stackru.com/questions/45388795/uncaught-referenceerror-vue-is-not-defined-when-put-vue-setting-in-index-html
window.Vue = Vue;
$(function() {
$('.datepicker').datepicker();
$('.dropdown-toggle').dropdown();
$('[data-toggle="popover"]').popover({
animation: true,
});
});
// Array Dupes Filter
// https://stackru.com/questions/6940103/how-do-i-make-an-array-with-unique-elements-i-e-remove-duplicates
function OmitArrDupes(a) {
var temp = {};
for (var i = 0; i < a.length; i++)
temp[a[i]] = true;
var r = [];
for (var k in temp)
r.push(k);
return r;
}
Как вы можете видеть, webpack используется исключительно для объединения общих библиотек и стилей, и в то же время он используется для хранения Vue и компонентов, которые я буду делать, и помогать со всей грязной работой.
Затем вы в конечном итоге получите:
И так ты сможешь застрять как я или, насколько я знаю, глупо, как я. Я превращаюсь в демен после того, как забрал это для производственного использования.
Судя по ошибкам консоли в chrome, 0.js загружен, но прерван из-за компонентов. Так что именно происходит? Мне действительно интересно узнать, как это на самом деле работает. Никогда еще не был так глубоко в фронтенде.
РЕДАКТИРОВАТЬ Это может быть связано с синтаксисом компонента. Может быть не так? хм.. Но если это так, Webpack будет не в тему.
<template>
<div :class="{ __disabled: disabled }" class="dropdown">
<button @click="toggle" class="btn btn-primary dropdown-toggle">
{{ currOption.name }}
</button>
<div v-if="opened" class="dropdown-menu">
<div v-for="o in options" :value="getVal(value)" @click="change(o)" :class="{__active: getVal(o) == getVal(value)}" class="dropdown_item">{{ getLabel(o) }}</div>
</div>
</div>
</template>
<script>
export default {
name: "base-select",
data() {
return {
opened: false,
currOption: {}
}
},
methods: {
getVal(opt) {
return !this.valueKey ? opt : opt[this.valueKey];
},
getLabel(opt) {
return !this.labelKey ? opt : opt[this.labelKey];
},
change(opt) {
this.$emit('input', opt)
this.opened = false;
if (this.onChange !== undefined) {
this.onChange(this.value);
}
},
toggle() {
if (this.disabled) {
return
}
// flip
this.opened = !this.opened;
}
},
props: {
value: {
required: true
},
options: {
type: Array,
required: true
},
valueKey: {
type: String,
required: false
},
labelKey: {
type: String,
required: false
},
onChange: {
type: Function,
required: false
},
disabled: {
type: Boolean,
default: false
}
}
}
</script>
<style scoped>
</style>
ОБНОВЛЕНИЕ 2 Попытка создать компонент test.vue, который имеет шаблон с привет
Тоже не сработало. Та же ошибка
2 ответа
Помимо того, что сказал @skribe,
Vue.component('base-select', () => import('./components/base-select.vue').then(m => m.default));
Это должно раскрыть все компоненты во всем мире. Для поддержки маршрутизации, вызываемой.NET Core, необходимо добавить дополнительный параметр с именем publicPath. publicPath позволяет вам глобально предоставлять файлы относительно объявленного вами корневого публичного пути, который в данном случае является publicPath.
module.exports = function (env) {
env = env || {};
var isProd = env.NODE_ENV === 'production';
// Setup base config for all environments
var config = {
entry: {
main: './Webpack/js/main'
},
output: {
// The format for the outputted files
filename: '[name].js',
// Put the files in "wwwroot/js/"
path: path.resolve(__dirname, 'wwwroot/dist/'),
// ============ ADD THE LINE BELOW ============= //
publicPath: '/dist/'
},
Я полагаю, что это может быть вызвано вашим синтаксисом асинхронного / динамического импорта, который недавно был изменен для vue-loader, который теперь использует "... модули ES внутри, чтобы воспользоваться преимуществами поднятия области webpack 3". (см. примечания к выпуску ниже)
Попробуй свой импорт вот так
Vue.component('base-select', () => import('./components/base-select.vue').then(m => m.default));
https://github.com/vuejs/vue-loader/releases/tag/v13.0.0
Изменить попробуйте изменить имя выходного файла чанка на относительный путь, как показано ниже.
output: {
// The format for the outputted files
filename: '[name].js',
// Put the files in "wwwroot/js/"
path: path.resolve(__dirname, 'wwwroot/dist/')
// Set chuck file name
chunkFilename:'../../js/[name].bundle.js'
},