Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[求助]element-plus的CSS如何CDN加载? #30

Closed
toimc opened this issue Nov 14, 2023 · 21 comments
Closed

[求助]element-plus的CSS如何CDN加载? #30

toimc opened this issue Nov 14, 2023 · 21 comments

Comments

@toimc
Copy link

toimc commented Nov 14, 2023

感谢作者的无私付出,有两个小疑问。

[1] 我想在项目中,让element-plus的css能够像在https://www.npmjs.com/package/vite-plugin-cdn-import 这个库中一样cdn加载,如何实现?

[2] 这个库 https://github.com/posva/unplugin-vue-router ,不知道作者清楚不?文件自动路由,但是配合当前vite-plugin-cdn2,即使设置了'vue-router' cdn加载,依旧在打包之后,会把vue-router打包进项目。

@nonzzz

@nonzzz
Copy link
Owner

nonzzz commented Nov 14, 2023

关于加入css的功能的话这个插件和vite-plugin-cdn-import是不一样的。你只需要加入spare属性就行。spare:['css文件即可'],关于vue-router没按照cdn加载的话我得研究下在给你答复 @toimc

@nonzzz
Copy link
Owner

nonzzz commented Nov 14, 2023

我目前查看了他的文档。检查你的本地项目是否包含vue-router/autovue-router/auto/routes 如果包含 就设置对应的aliases.

具体配置如下

cdn({
 modules: ['vue', {name:'ElementPlus',aliases:['es'],spare:['https://cdn.jsdelivr.net/npm/element-plus@2.4.2/dist/index.min.css'], {name:'vue-router',aliases:['auto','auto/routes']}}
})

@toimc
Copy link
Author

toimc commented Nov 15, 2023

非常感谢上面的回复。

[1]

我尝试了一下,vue-router/auto的问题解决了,但是spare属性未生效,生成的html中未发现css:

这个是新生成的html:

<!doctype html>
<html lang="en">
  <head>
    <script src="https://cdn.jsdelivr.net/npm/vue@3.3.8/dist/vue.global.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/element-plus@2.4.2/dist/index.full.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue-demi@0.14.6/lib/index.iife.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/vue-router@4.2.5/dist/vue-router.global.js"></script>
    <script src="https://cdn.jsdelivr.net/npm/pinia@2.1.7/dist/pinia.iife.js"></script>

    <meta charset="UTF-8" />
    <link rel="icon" href="/favicon.ico" />
    <meta
      name="viewport"
      id="viewport"
      content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width, viewport-fit=cover"
    />
    <title>Vite App</title>
    <script type="module" crossorigin src="/assets/index-e808e22b.js"></script>
    <link rel="stylesheet" href="/assets/index-f984f7b7.css">
  <link rel="manifest" href="/manifest.webmanifest"></head>
  <body class="m-safe">
    <div id="app"></div>
    
  </body>
</html>

配置如下:

modules: [
          'vue',
          { name: 'element-plus', aliases: ['es', 'lib'] },
          'vue-demi',
          {
            name: 'ElementPlus',
            aliases: ['es'],
            spare: ['https://cdn.jsdelivr.net/npm/element-plus@2.4.2/dist/index.min.css']
          },
          { name: 'vue-router', aliases: ['auto', 'auto/routes'] },
          'pinia'
        ],
        logLevel: 'slient'

[2] 还有一个构建过程中的日志打印问题:

image 为什么开启了logLevl: 'slient' 还是会打印

@nonzzz
Copy link
Owner

nonzzz commented Nov 15, 2023

这个log 应该是我无心之举。后面版本会进行修复

@nonzzz
Copy link
Owner

nonzzz commented Nov 15, 2023

我应该是看错了。ElementPlus 这个应该没有用你自己配置的element-plus 是正确的。只需要把spare 移进去。

@toimc
Copy link
Author

toimc commented Nov 15, 2023

sorry,我发现问题了,我嵌套错位置了。

新配置如下:

modules: [
          'vue',
          {
            name: 'element-plus',
            aliases: ['es', 'lib'],
            spare: ['https://cdn.jsdelivr.net/npm/element-plus@2.4.2/dist/index.min.css']
          },
          'vue-demi',
          { name: 'vue-router', aliases: ['auto', 'auto/routes'] },
          'pinia'
        ],
image

[1]为什么项目中没有使用.prod的js,而是全部使用的是global.js,这一块如何设置?

[2]如果使用 unpkg.com作为url,我觉得如下写resolve非常low,有没有优化建议?

resolve: (base, { name, version }) => {
          // vue@3.3.8/dist/vue.global.js
          switch (name) {
            case 'vue':
            case 'vue-router':
              return `${base}/${name}@${version}/dist/${name}.global.prod.js`
            case 'element-plus':
              return `${base}/${name}@${version}/dist/index.full.min.js`
            case 'vue-demi':
              return `${base}/${name}@${version}/lib/index.iife.js`
            default:
              return `${base}/${name}@${version}/dist/${name}.iife.prod.js`
          }
        }

@nonzzz
Copy link
Owner

nonzzz commented Nov 15, 2023

你可以使用relativeModule

[
  { name: 'vue', relativeModule: './dist/vue.global.prod.js' },
  {
    name: 'element-plus',
    aliases: ['es', 'lib'],
    relativeModule: './dist/index.full.min.js',
    spare: ['https://cdn.jsdelivr.net/npm/element-plus@2.4.2/dist/index.min.css']
  },
  { name: 'vue-demi', relativeModule: './dist/index.iife.js' },
  { name: 'vue-router', aliases: ['auto', 'auto/routes'], relativeModule: './dist/vue-router.global.prod.js' },
  { name: 'pinia', relativeModule: './dist/iife.prod.js' }
]

@toimc
Copy link
Author

toimc commented Nov 15, 2023

上面的解决方案非常棒,非常感谢。

有两个问题:

[1] 使用unplugin-vue-router 插件之后,如果使用 { name: 'vue-router', aliases: ['auto', 'auto/routes'], relativeModule: './dist/vue-router.global.prod.js' } 是可以把vue-router使用cdn加载的,但是项目打包会出问题,所以的项目组件都未成功生成:

这个是把vue-router排除在外的情况:

✓ 108 modules transformed.
dist/manifest.webmanifest                          0.29 kB
dist/index.html                                    1.16 kB │ gzip:  0.52 kB
dist/assets/index-f984f7b7.css                    20.77 kB │ gzip:  4.76 kB
dist/assets/404-2711b914.js                        0.38 kB │ gzip:  0.27 kB
dist/assets/zh-cn-2b877b8e.js                      1.61 kB │ gzip:  1.12 kB
dist/assets/zh-cn-476220b1.js                      2.28 kB │ gzip:  0.90 kB
dist/assets/single-page-538c28e2.js                2.46 kB │ gzip:  1.14 kB
dist/assets/en-1fb5af88.js                         2.48 kB │ gzip:  0.66 kB
dist/assets/en-3f1991e3.js                         2.79 kB │ gzip:  1.22 kB
dist/assets/workbox-window.prod.es5-a7b12eab.js    5.29 kB │ gzip:  2.20 kB
dist/assets/index-1091f9ec.js                    209.65 kB │ gzip: 70.56 kB

未排除在外的情况:

✓ 253 modules transformed.
dist/manifest.webmanifest                                               0.29 kB
dist/index.html                                                         1.07 kB │ gzip:  0.51 kB
dist/assets/about-4d995ba2.css                                          0.09 kB │ gzip:  0.10 kB
dist/assets/draggable-85402e9d.css                                      0.12 kB │ gzip:  0.13 kB
dist/assets/ep-icon-picker-7eb084ee.css                                 0.12 kB │ gzip:  0.12 kB
dist/assets/CollapseTransition-e6724fa4.css                             0.12 kB │ gzip:  0.11 kB
dist/assets/avatars-6ef93914.css                                        0.15 kB │ gzip:  0.12 kB
dist/assets/index-4e7f02f1.css                                          0.20 kB │ gzip:  0.12 kB
dist/assets/notice-message-bf637873.css                                 0.35 kB │ gzip:  0.23 kB
dist/assets/index-3dc731e4.css                                         26.58 kB │ gzip:  5.72 kB
dist/assets/route-block-83d24a4e.js                                     0.03 kB │ gzip:  0.05 kB
dist/assets/Popover-8e086f8e.js                                         0.10 kB │ gzip:  0.11 kB
dist/assets/menu2-8a94d0c8.js                                           0.18 kB │ gzip:  0.17 kB
dist/assets/menu1-2-7d501830.js                                         0.19 kB │ gzip:  0.17 kB
dist/assets/menu1-1-1-032dab54.js                                       0.19 kB │ gzip
...  // 省略掉
dist/assets/index-610b58d1.js                                         241.45 kB │ gzip: 81.92 kB

优化index.js大概优化了40kb左右。

尝试下面的配置,解决:

{
    name: 'vue-router',
    aliases: ['auto'],
    relativeModule: './dist/vue-router.global.prod.js'
},

[2] 删除vue-router,在开发模式下,项目能够正常启动,但是build&preview会出错:

Uncaught TypeError: Cannot read properties of undefined (reading 'BaseTransition')
    at index-abc148f6.js:23:55328
(anonymous) @ index-abc148f6.js:23

看了一下,应该全是vue core的内容。

解决尝试1:

image

看了一下vue在head部分导入,没有问题,链接https://unpkg.com/vue@3.3.8/dist/vue.global.prod.js正常访问

解决尝试2:

起初我怀疑是关闭了AutoImport与Components在production模式下的作用,resolvers: isProd ? [] : [ElementPlusResolver()],实际上,无效。

======
目前卡在这里了,望回复。

@nonzzz
Copy link
Owner

nonzzz commented Nov 15, 2023

具体使用了哪些插件呢。能提供一份配置表吗

@toimc
Copy link
Author

toimc commented Nov 15, 2023

当然可以,package.json

{
  // ...
  },
  "dependencies": {
    "@unocss/reset": "^0.57.4",
    "@vueuse/core": "^10.6.1",
    "dayjs": "^1.11.10",
    "element-plus": "^2.4.2",
    "gsap": "^3.12.2",
    "pinia": "^2.1.7",
    "pinia-plugin-persistedstate": "^3.2.0",
    "sortablejs": "^1.15.0",
    "vue": "^3.3.8",
    "vue-i18n": "^9.6.5",
    "vue-router": "^4.2.5"
  },
  "devDependencies": {
    "@iconify/json": "^2.2.142",
    "@iconify/vue": "^4.1.1",
    "@intlify/unplugin-vue-i18n": "^1.5.0",
    // ...
    "@unocss/preset-wind": "^0.57.2",
    "@vitejs/plugin-vue": "^4.4.1",
    "@vitejs/plugin-vue-jsx": "^3.0.2",
    "rollup-plugin-visualizer": "^5.9.2",
    "sass": "^1.69.5",
    "unocss": "^0.57.2",
    "unplugin-auto-import": "^0.16.7",
    "unplugin-vue-components": "^0.25.2",
    "unplugin-vue-router": "^0.7.0",
    "vite": "^4.5.0",
    "vite-plugin-cdn2": "^0.15.1",
    "vite-plugin-mock": "^3.0.0",
    "vite-plugin-pwa": "^0.16.7",
    "vite-plugin-svg-icons": "^2.0.1",
    "vite-plugin-vue-layouts": "^0.8.0"
  }
}

vite.config.ts:

// ..
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'

import { VueRouterAutoImports } from 'unplugin-vue-router'

import VueRouter from 'unplugin-vue-router/vite'
import AutoImport from 'unplugin-auto-import/vite'
import Components from 'unplugin-vue-components/vite'

// @ts-ignore
import Layouts from 'vite-plugin-vue-layouts'
import UnoCSS from 'unocss/vite'

import { ElementPlusResolver } from 'unplugin-vue-components/resolvers'

import { VitePWA } from 'vite-plugin-pwa'

import { viteMockServe } from 'vite-plugin-mock'
import { createSvgIconsPlugin } from 'vite-plugin-svg-icons'
import I18n from '@intlify/unplugin-vue-i18n/vite'
import { visualizer } from 'rollup-plugin-visualizer'

import { cdn } from 'vite-plugin-cdn2'


// https://vitejs.dev/config/
export default defineConfig(({ mode, command }) => {
  const isProd = mode === 'production'
  return {
    plugins: [
      VueRouter(),
      vue({
        script: {
          defineModel: true,
          propsDestructure: true
        }
      }),
      vueJsx(),
      UnoCSS(),
      AutoImport({
        include: [
          /\.[tj]sx?$/, // .ts, .tsx, .js, .jsx
          /\.vue$/,
          /\.vue\?vue/, // .vue
          /\.md$/ // .md
        ],

        // global imports to register
        imports: [
          // presets
          'vue',
          // 'vue-router'
          VueRouterAutoImports,
          '@vueuse/core'
        ],
        resolvers: isProd ? [] : [ElementPlusResolver()],
        vueTemplate: true
      }),
      Components({
        directoryAsNamespace: false,
        collapseSamePrefixes: true,
        resolvers: isProd ? [] : [ElementPlusResolver()]
      }),
      Layouts({
        layoutsDirs: 'src/layouts',
        defaultLayout: 'default'
      }),
      VitePWA({
        manifest: {
          name: 'Vite App',
          short_name: 'Vite App',
          theme_color: '#ffffff',
          icons: [
            {
              src: '/192x192.png',
              sizes: '192x192',
              type: 'image/png'
            },
            {
              src: '/512x512.png',
              sizes: '512x512',
              type: 'image/png'
            }
          ]
        },
        registerType: 'autoUpdate'
      }),
      viteMockServe({
        mockPath: 'mock',
        enable: false
      }),
      createSvgIconsPlugin({
        // 指定需要缓存的图标文件夹
        iconDirs: [path.resolve(process.cwd(), 'src/assets/icons')],
        // 指定symbolId格式
        symbolId: 'icon-[dir]-[name]'
      }),
      I18n({
        include: [path.resolve(__dirname, './locales/**')],
        // 说明:由于配置了modules/i18n.ts中默认为legacy: false
        // 所以禁止修改
        compositionOnly: true,
        jitCompilation: true
      }),
      visualizer({
        open: true
      }),
      cdn({
        url: 'https://unpkg.com',
        modules: [
          { name: 'vue', relativeModule: './dist/vue.global.prod.js' },
          { name: 'vue-demi', relativeModule: './dist/index.iife.js' },
          {
            name: 'vue-router',
            aliases: ['auto'],
            relativeModule: './dist/vue-router.global.prod.js'
          },
          {
            name: 'element-plus',
            relativeModule: './dist/index.full.min.js',
            aliases: ['es', 'lib'],
            spare: [
              'https://cdn.jsdelivr.net/npm/element-plus@2.4.2/dist/index.min.css',
              'https://cdn.jsdelivr.net/npm/element-plus@2.4.2/theme-chalk/dark/css-vars.css'
            ]
          },
          { name: 'pinia', relativeModule: './dist/iife.prod.js' }
        ],
        logLevel: 'slient'
      })
    ],
    resolve: {
      alias: {
        '@': fileURLToPath(new URL('./src', import.meta.url))
      }
    },
    server: {
      host: '0.0.0.0'
    }
  }
})

@nonzzz
Copy link
Owner

nonzzz commented Nov 15, 2023

@toimc 我在本地制作了一个最小复现demo。我觉得你并不需要isProd 这个字段。autoImportcomponents的resolvers照常使用即可。不需要空数组。同时因为按需引入了。这里是题外话我觉得既然按需引入了那么ElementPlus 如果是轻度使用完全可以不用cdn.直接打包进去即可。因为这2个插件会附带引入css 打包进chunk这一点你可以注意一下。关于router的这个我没遇到问题。

@toimc
Copy link
Author

toimc commented Nov 15, 2023

我做了一个最小 demo,https://github.com/toimc/vite-vue-cdn-demo ,你可以在你本地试一下,pnpm dev正常,pnpm build-only && pnpm preview,无法运行。

关于:

我觉得你并不需要isProd 这个字段,autoImport 和components的resolvers照常使用即可——说明一下我这么做的原因:

理由一:由于项目中使用到component动态组件,有一些场景下,需要动态从服务端传递过来一些可能在当前resolver下没有打包进来了element-plus中的组件,所以要这么干;

理由二:由于"这2个插件会附带引入css 打包进chunk",正如你所说,我发现这2个插件会导致css会有100kb的增加,非常不nice,我直接考虑全部cdn加载,避免重复打包。

关于router的这个我没遇到问题——我上面已经回复,我目前的解决方案,可以参看最小 demo中的vite配置。

非常感谢!!!

@nonzzz
Copy link
Owner

nonzzz commented Nov 15, 2023

关于router的这个问题。 我暂时没什么好思路。这个包不会特别大我会找个时间研究下这个插件具体的工作流。目前你可以先把他移除。以及 tryScanGlobalName 去推测全局变量并不是万能的。我在用你的demo的时候发现了警告这时候你应该手动传入globalName。这个tryScanGlobalName我也会进行优化尝试覆盖更多的mangle包

@nonzzz
Copy link
Owner

nonzzz commented Nov 15, 2023

Pinia和VueDemi 配置错了应该是 { name: 'vue-demi', relativeModule: './lib/index.iife.js' },{ name: 'pinia', relativeModule: './dist/pinia.iife.prod.js' }

@toimc
Copy link
Author

toimc commented Nov 15, 2023

关于router的这个问题。 我暂时没什么好思路。这个包不会特别大我会找个时间研究下这个插件具体的工作流。目前你可以先把他移除。以及 tryScanGlobalName 去推测全局变量并不是万能的。我在用你的demo的时候发现了警告这时候你应该手动传入globalName。这个tryScanGlobalName我也会进行优化尝试覆盖更多的mangle包

是的,我还发现,如果这样设置resolvers: isProd ? [] : [ElementPlusResolver()],,打包之后,即使在head部分有加载css,但是依旧,页面加载不成功样式。
image
image

network中无请求:

image

见代码:

toimc/vite-vue-cdn-demo@4693e2e?diff=split#diff-6a3b01ba97829c9566ef2d8dc466ffcffb4bdac08706d3d6319e42e0aa6890ddR54

toimc/vite-vue-cdn-demo@4693e2e?diff=split#diff-6a3b01ba97829c9566ef2d8dc466ffcffb4bdac08706d3d6319e42e0aa6890ddR48

@nonzzz
Copy link
Owner

nonzzz commented Nov 15, 2023

看起来是插件的bug。我会进行一个修复。 应急措施的话就得看文档了。

@toimc
Copy link
Author

toimc commented Nov 15, 2023

你是指vite-plugin-cdn插件有问题,还是指AutoImport及Components这两个插件有问题?

冒昧问一下,有什么思路没有?卡在这里了,想压缩项目打包的体积。

尝试一:rollup插件方式External + html静态资源导入又与vite-plugin-pwa这个插件冲突,打包之后html中无js,css
尝试二:rollup插件方式external + vite-plugin-html静态资源导入,资源导入的位置有问题,样式部分需要另外的js逻辑,无法external vue-router(这个与此插件表现一致)
尝试三:使用vite-plugin-cdn-import,与AutoImport及Components这两个插件不兼容,同时打包的文件,会重复打包i18n的locales翻译 js文件,即使已经external掉。

@nonzzz
Copy link
Owner

nonzzz commented Nov 15, 2023

unplugin-vue-router这个插件。 他的实现目前在我看来有点黑盒。这么说吧目前社区里面的external插件多多少少都有些不足 但是由于vite社区热衷于编译魔法导致一些edge case无法被很好的覆盖。

@nonzzz
Copy link
Owner

nonzzz commented Nov 15, 2023

因为目前这类的插件实现原理都是大同小异无非是看谁的external做的更好罢了。

@nonzzz
Copy link
Owner

nonzzz commented Nov 15, 2023

我发布了0.15.2对插入问题进行了一个修复

@toimc
Copy link
Author

toimc commented Nov 15, 2023

我发布了0.15.2对插入问题进行了一个修复

经过我的尝试,已经OK了,感谢开源作者无私的付出。

cdn({
        url: 'https://unpkg.com',
        modules: [
          { name: 'vue', relativeModule: './dist/vue.global.prod.js' },
          { name: 'vue-demi', relativeModule: './lib/index.iife.js'  },
          // {
          //   name: 'vue-router',
          //   aliases: ['auto'],
          //   relativeModule: './dist/vue-router.global.prod.js'
          // }, // 这一块未解决,参考 https://github.com/nonzzz/vite-plugin-cdn/issues/30
          {
            name: 'element-plus',
            relativeModule: './dist/index.full.min.js',
            aliases: ['es', 'lib'],
            spare: [
              'https://unpkg.com/element-plus@2.4.2/dist/index.css',
              'https://unpkg.com/element-plus@2.4.2/theme-chalk/dark/css-vars.css'
            ]
          },
          { name: 'pinia', relativeModule: './dist/pinia.iife.prod.js'  },
          { name: 'vue-i18n', relativeModule: './dist/vue-i18n.global.prod.js' },
          { name: 'sortablejs', global: 'Sortablejs', relativeModule: './Sortable.min.js' }
        ]
      })

最终配置,提供给有缘人。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants