diff --git a/.config/.browserslistrc b/.config/.browserslistrc deleted file mode 100644 index f9018f91..00000000 --- a/.config/.browserslistrc +++ /dev/null @@ -1,10 +0,0 @@ -# docs: https://www.npmjs.com/package/browserslist -# run '$ npx browserslist' in .config/ directory to see wich browsers are selected by your queries for [production]. - -[development] -last 2 chrome versions -last 2 firefox versions - -[production] -last 4 versions -not IE <= 11 \ No newline at end of file diff --git a/.config/vite.config.js b/.config/vite.config.js new file mode 100644 index 00000000..b2c9b2db --- /dev/null +++ b/.config/vite.config.js @@ -0,0 +1,55 @@ +import { resolve } from "path"; +import vue from "@vitejs/plugin-vue"; +import del from "rollup-plugin-delete"; +import ESLintPlugin from '@modyqyw/vite-plugin-eslint'; +import StylelintPlugin from 'vite-plugin-stylelint'; + +export default { + plugins: [ + vue(), + ESLintPlugin({ + overrideConfigFile: resolve(__dirname, "./.eslintrc.js"), + include: "../src/**/*.{js,vue}", + }), + StylelintPlugin({ + files: '../src/**/*.{vue,css,sass,scss}', + configFile: resolve(__dirname, './.stylelintrc.js') + }) + ], + clearScreen: false, + css: { + postcss: resolve(__dirname, "../.config/postcss.config.js"), + }, + resolve: { + extensions: ["*", ".js", ".vue", ".json"], + alias: { + vue: "vue/dist/vue.esm-bundler.js", + "@": resolve(__dirname, "../src/"), + "@shopify-directory": resolve(__dirname, "../shopify/"), + }, + }, + build: { + rollupOptions: { + input: { + bundle: resolve(__dirname, "../src/main.js"), + }, + output: { + entryFileNames: `[name].js`, + chunkFileNames: `[name].js`, + assetFileNames: (assetInfo) => + assetInfo.name.split("/").pop().split(".").shift() == "main" + ? "bundle.css" + : "[name].[ext]", + }, + plugins: [ + process.env.NODE_ENV == "production" && + del({ + targets: ["../shopify/assets/**/*", "!../shopify/assets/*static*"], + }), + ], + }, + outDir: resolve(__dirname, "../shopify/assets"), + assetsDir: ".", + emptyOutDir: false, + }, +}; diff --git a/.config/webpack/webpack.common.js b/.config/webpack/webpack.common.js deleted file mode 100644 index 6bf6da9d..00000000 --- a/.config/webpack/webpack.common.js +++ /dev/null @@ -1,92 +0,0 @@ -const path = require('path') -const webpack = require('webpack') -const { CleanWebpackPlugin } = require('clean-webpack-plugin') -const MiniCssExtractPlugin = require('mini-css-extract-plugin') -const { VueLoaderPlugin } = require('vue-loader') - -module.exports = { - stats: 'minimal', - entry: path.resolve(__dirname, '../../src/main.js'), - output: { - path: path.resolve(__dirname, '../../shopify/assets/'), - filename: 'bundle.js' - }, - resolve: { - extensions: ['*', '.js', '.vue', '.json'], - alias: { - 'vue$': 'vue/dist/vue.esm-bundler.js', - '@': path.resolve(__dirname, '../../src/'), - '@shopify-directory': path.resolve(__dirname, '../../shopify/') - } - }, - module: { - rules: [ - { - test: /\.vue$/, - loader: 'vue-loader' - }, - { - test: /\.(png|svg|jpg|gif)$/, - use: [ - { - loader: 'url-loader', - options: { - limit: 8192 - } - } - ] - }, - ... (() => { - const rules = [] - - const loaders = [ - { test: /\.(css|postcss)$/i }, - { test: /\.s[ac]ss$/i, loader: 'sass-loader' }, - { test: /\.less$/i, loader: 'less-loader' }, - { test: /\.styl$/i, loader: 'stylus-loader' } - ] - - loaders.forEach((element, index) => { - rules.push({ - test: element.test, - use: [ - MiniCssExtractPlugin.loader, - 'css-loader', - { - loader: 'postcss-loader', - options: { - postcssOptions: require(path.resolve(__dirname, '../postcss.config.js')) - } - } - ] - }) - - if (element.loader) rules[index].use.push(element.loader) - }) - - return rules - })() - ] - }, - plugins: [ - /** - * don't clean files with the 'static' keyword in their filename - * docs: https://github.com/johnagan/clean-webpack-plugin - */ - new CleanWebpackPlugin({ - cleanOnceBeforeBuildPatterns: ['**/*', '!*static*'] - }), - /** - * docs: https://webpack.js.org/plugins/mini-css-extract-plugin - */ - new MiniCssExtractPlugin({ - filename: './bundle.css', - chunkFilename: '[id].css' - }), - new VueLoaderPlugin(), - new webpack.DefinePlugin({ - __VUE_OPTIONS_API__: 'true', - __VUE_PROD_DEVTOOLS__: 'false' - }) - ] -} \ No newline at end of file diff --git a/.config/webpack/webpack.dev.js b/.config/webpack/webpack.dev.js deleted file mode 100644 index fa933854..00000000 --- a/.config/webpack/webpack.dev.js +++ /dev/null @@ -1,25 +0,0 @@ -const path = require('path') -const { merge } = require('webpack-merge') -const ESLintPlugin = require('eslint-webpack-plugin') -const StylelintPlugin = require('stylelint-webpack-plugin') -const common = require('./webpack.common.js') - -module.exports = merge(common, { - mode: 'development', - plugins: [ - /** - * docs: https://www.npmjs.com/package/eslint-webpack-plugin - */ - new ESLintPlugin({ - files: 'src/**/*.{js,vue}', - overrideConfigFile: path.resolve(__dirname, '../.eslintrc.js') - }), - /** - * docs: https://www.npmjs.com/package/stylelint-webpack-plugin - */ - new StylelintPlugin({ - files: 'src/**/*.{vue,css,sass,scss}', - configFile: path.resolve(__dirname, '../.stylelintrc.js') - }) - ] -}) \ No newline at end of file diff --git a/.config/webpack/webpack.prod.js b/.config/webpack/webpack.prod.js deleted file mode 100644 index 6635155d..00000000 --- a/.config/webpack/webpack.prod.js +++ /dev/null @@ -1,44 +0,0 @@ -const { merge } = require('webpack-merge') -const TerserPlugin = require('terser-webpack-plugin') // included in webpack 5, no need to add to package.json -const CssMinimizerPlugin = require('css-minimizer-webpack-plugin') -const common = require('./webpack.common.js') - -module.exports = merge(common, { - mode: 'production', - performance: { - hints: false - }, - module: { - rules: [ - { - test: /\.js$/, - loader: 'babel-loader', - exclude: /node_modules/, - options: { - presets: [ '@babel/preset-env' ], - plugins: [ '@babel/plugin-transform-runtime' ] - } - } - ] - }, - optimization: { - minimize: true, - minimizer: [ - /** - * docs: https://webpack.js.org/plugins/terser-webpack-plugin - */ - new TerserPlugin({ - terserOptions: { - format: { - comments: /@license/i // preserve license comments - } - }, - extractComments: false - }), - /** - * docs: https://webpack.js.org/plugins/css-minimizer-webpack-plugin - */ - new CssMinimizerPlugin() - ] - } -}) \ No newline at end of file diff --git a/package.json b/package.json index 11b6cc84..28321ada 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,11 @@ "version": "4.4.1", "license": "MIT", "scripts": { - "start": "run-p -sr shopify:serve webpack:watch", - "deploy": "run-s webpack:build && cd shopify && shopify theme push", - "deploy:new": "run-s webpack:build && cd shopify && shopify theme push --unpublished", - "webpack:watch": "cross-env NODE_ENV=development BROWSERSLIST_ENV=development BROWSERSLIST_CONFIG=.config/.browserslistrc webpack --config .config/webpack/webpack.dev.js --watch --progress", - "webpack:build": "cross-env NODE_ENV=production BROWSERSLIST_ENV=production BROWSERSLIST_CONFIG=.config/.browserslistrc webpack --config .config/webpack/webpack.prod.js --progress", + "start": "run-p -sr shopify:serve vite:watch", + "deploy": "run-s vite:build && cd shopify && shopify theme push", + "deploy:new": "run-s vite:build && cd shopify && shopify theme push --unpublished", + "vite:watch": "cross-env NODE_ENV=development vite build --watch --mode 'development' --config .config/vite.config.js", + "vite:build": "cross-env NODE_ENV=production vite build --mode 'production' --config .config/vite.config.js", "shopify:serve": "cd shopify && shopify theme serve", "shopify:pull": "cd shopify && shopify theme pull", "lint": "run-s -c lint:*", @@ -22,37 +22,25 @@ "fix:shopify": "cd shopify && shopify theme check -a" }, "dependencies": { - "tailwindcss": "^3.0.2", - "vue": "^3.2.26", + "tailwindcss": "^3.1.6", + "vue": "^3.2.37", "vuex": "^4.0.2" }, "devDependencies": { - "@babel/core": "^7.16.0", - "@babel/plugin-transform-runtime": "^7.16.4", - "@babel/preset-env": "^7.16.4", - "@vue/compiler-sfc": "^3.2.26", - "autoprefixer": "^10.4.0", - "babel-loader": "^8.2.3", - "clean-webpack-plugin": "^4.0.0", + "@vitejs/plugin-vue": "^3.0.0", + "vite": "^3.0.0", + "@modyqyw/vite-plugin-eslint": "^2.0.3", + "rollup-plugin-delete": "^2.0.0", + "autoprefixer": "^10.4.7", "cross-env": "^7.0.3", - "css-loader": "^6.5.1", - "css-minimizer-webpack-plugin": "^3.2.0", - "eslint": "^8.4.1", - "eslint-plugin-vue": "^8.2.0", - "eslint-webpack-plugin": "^3.1.1", - "mini-css-extract-plugin": "^2.4.5", + "eslint": "^8.20.0", + "eslint-plugin-vue": "^9.2.0", "npm-run-all": "^4.1.5", - "postcss": "^8.4.5", - "postcss-html": "^1.3.0", - "postcss-import": "^14.0.2", - "postcss-loader": "^6.2.1", - "stylelint": "^14.1.0", - "stylelint-config-recommended": "^6.0.0", - "stylelint-webpack-plugin": "^3.1.0", - "url-loader": "^4.1.1", - "vue-loader": "^16.8.3", - "webpack": "^5.65.0", - "webpack-cli": "^4.9.1", - "webpack-merge": "^5.8.0" + "postcss": "^8.4.14", + "postcss-html": "^1.5.0", + "postcss-import": "^14.1.0", + "stylelint": "^14.9.1", + "stylelint-config-recommended": "^8.0.0", + "vite-plugin-stylelint": "^3.0.2" } } diff --git a/src/main.js b/src/main.js index b9b3f594..2dbbeb7a 100644 --- a/src/main.js +++ b/src/main.js @@ -1,94 +1,94 @@ /** * imports */ -import { createApp } from 'vue' -import { createStore } from 'vuex' -import './css/main.css' + +import { createApp } from "vue"; +import { createStore } from "vuex"; +import "./css/main.css"; /** * vuex * auto-import all modules and prepare shared store */ -const vuexModules = require.context('./vue/store/', true, /\.js$/) -const modules = {} +const vuexModules = import.meta.globEager("./vue/store/**/*.js"); +const modules = {}; + +Object.entries(vuexModules).forEach(([path, definition]) => { + const name = path + .replace(/\/vue\/store/g, "") + .replace(/\.(\/|js)/g, "") + .replace(/\s/g, "-"); -vuexModules.keys().forEach(key => { - const name = key.replace(/\.(\/|js)/g, '').replace(/\s/g, '-') - modules[name] = vuexModules(key).default -}) + modules[name] = definition.default; +}); const store = createStore({ - strict: process.env.NODE_ENV !== 'production', - modules -}) + strict: process.env.NODE_ENV !== "production", + modules, +}); /** * create vue instance function */ -const createVueApp = (name) => { - const app = createApp({ name }) +const createVueApp = () => { + const app = createApp({}); /** * vue components * auto-import all vue components */ - const vueComponents = require.context('./vue/components/', true, /\.(vue|js)$/) + const components = import.meta.globEager("./vue/components/**/*.vue"); - vueComponents.keys().forEach(key => { - const component = vueComponents(key).default + Object.entries(components).forEach(([path, definition]) => { + const componentName = path + .replace(/\/vue\/components/g, "") + .replace(/\.(\/|vue|js)/g, "") + .replace(/(\/|-|_|\s)\w/g, (match) => match.slice(1).toUpperCase()); - // if a component has a name defined use the name, else use the path as the component name - const name = component.name - ? component.name - : key.replace(/\.(\/|vue|js)/g, '').replace(/(\/|-|_|\s)\w/g, (match) => match.slice(1).toUpperCase()) - - app.component(name, component) - }) + app.component(componentName, definition.default); + }); /** * vue mixins * auto-register all mixins with a 'global' keyword in their filename */ - const mixins = require.context('./vue/mixins/', true, /.*global.*\.js$/) + // const mixins = require.context('./vue/mixins/', true, /.*global.*\.js$/) + const mixins = import.meta.globEager("./vue/mixins/*.js"); - mixins.keys().forEach(key => { - app.mixin(mixins(key).default) - }) + Object.entries(mixins).forEach(([path, definition]) => { + app.mixin(definition.default); + }); /** * vue directives * auto-register all directives with a 'global' keyword in their filename */ - const directives = require.context('./vue/directives/', true, /.*global.*\.js$/) + const directives = import.meta.globEager("./vue/directives/*.js"); - directives.keys().forEach(key => { - const directive = directives(key).default - app.directive(directive.name, directive.directive) - }) + Object.entries(directives).forEach(([path, definition]) => { + const directive = definition.default; + app.directive(directive.name, directive.directive); + }); /** * vue plugins * extend with additional features */ - app.use(store) + app.use(store); - return app -} + return app; +}; /** * create and mount vue instance(s) */ -const appElement = document.querySelector('#app') +const appElement = document.querySelector("#app"); if (appElement) { - createVueApp().mount(appElement) + createVueApp().mount(appElement); } else { - const vueElements = document.querySelectorAll('[vue]') - if (vueElements) { - vueElements.forEach(el => { - createVueApp(el.dataset.name).mount(el) - }) - } + const vueElements = document.querySelectorAll("[vue]"); + if (vueElements) vueElements.forEach((el) => createVueApp().mount(el)); } /** @@ -104,19 +104,21 @@ if (appElement) { * {% endschema %} */ if (Shopify.designMode) { - document.addEventListener('shopify:section:load', (event) => { - if (event.target.classList.value.includes('vue')) { - createVueApp().mount(event.target) + document.addEventListener("shopify:section:load", (event) => { + if (event.target.classList.value.includes("vue")) { + createVueApp().mount(event.target); } - }) -} else if (!Shopify.designMode && process.env.NODE_ENV === 'development') { + }); +} else if (!Shopify.designMode && process.env.NODE_ENV === "development") { new MutationObserver((mutationsList) => { - mutationsList.forEach(record => { - const vue = Array.from(record.addedNodes).find(node => node.classList && node.classList.value.includes('vue')) - if (vue) window.location.reload() - }) + mutationsList.forEach((record) => { + const vue = Array.from(record.addedNodes).find( + (node) => node.classList && node.classList.value.includes("vue") + ); + if (vue) window.location.reload(); + }); }).observe(document.body, { childList: true, - subtree: true - }) + subtree: true, + }); }