• home > webfront > ECMAS > vue3 >

    vue2升级vue3:webpack vue-loader 打包配置

    Author:zhoulujun Date:

    虽然vite 很香,但是vite rollup 动态加载,多页面 等问题比较难搞。webpack vue3需要升级的npm 包有:vue-loader vue-template-compiler "

    如果没有啥特别的需求还是推荐vue-cli!

    vite  vue3 TSX项目

    虽然vite 很香,但是vite  rollup 动态加载,多页面 等问题比较难搞

    vite的缺点

    wepback  __webpack_public_path__ 没有找到好的实践方案。

    __webpack_public_path__ = window.BK_STATIC_URL;

    第二个,动态加载css 里面的资源

    /**
     * @file 替换 asset css 中的 BK_STATIC_URL,__webpack_public_path__ 没法解决 asset 里静态资源的 url
     * @author
     */
    
    const { extname } = require('path');
    
    class ReplaceCSSStaticUrlPlugin {
      apply(compiler) {
        // emit: 在生成资源并输出到目录之前
        compiler.hooks.emit.tapAsync('ReplaceCSSStaticUrlPlugin', (compilation, callback) => {
          const assets = Object.keys(compilation.assets);
          const assetsLen = assets.length;
    
          for (let i = 0; i < assetsLen; i++) {
            const fileName = assets[i];
            const name = extname(fileName);
            if (extname(fileName) !== '.css') {
              continue;
            }
            const asset = compilation.assets[fileName];
            let minifyFileContent = asset.source().toString()
              .replace(
                /\{\{\s*BK_STATIC_URL\s*\}\}/g,
                () => '../',
              );
            compilation.assets[fileName] = {
              // 返回文件内容
              source: () => minifyFileContent,
              // 返回文件大小
              size: () => Buffer.byteLength(minifyFileContent, 'utf8'),
            };
          }
    
          callback();
        });
      }
    }
    module.exports = ReplaceCSSStaticUrlPlugin;


    虽然有 vite-plugin-dynamic-publicpath 等插件,但是并不是非常好使

    多页面配置,主要还是修改rollup配置

    build: {
      assetsDir: 'assets', // 指定生成静态资源的存放路径
      rollupOptions: {
          input: {
            admin: path.resolve(__dirname, 'src/index.html'),
            page: path.resolve(__dirname, 'src/page/index.html'),
            index: path.resolve(__dirname, 'src/index/index.html'),
          },
          output: {
            chunkFileNames: 'static/js/[name]-[hash].js',
            entryFileNames: 'static/js/[name]-[hash].js',
            assetFileNames: 'static/[ext]/[name]-[hash].[ext]',
          }
        },
    }

    多页面更多的资料,网上很多,这里推荐几篇文章:

    vue+vite多页应用配置及页面路径更改 https://juejin.cn/post/7004784113706090526

    Vite 入门以及从 webpack 切换到 Vite 遇到的问题总结  https://jishuin.proginn.com/p/763bfbd4f55a

    多页面貌似解决了,当rollup 打包完成后,都在二级目录,虽然有办法解决,但是一路搞下来,不想在折腾了


    想来想去还是webpack 原有配置方便

    webpack vue3 TSX

    只需要升级npm 包:vue-loader vue-template-compiler"

    1. vue-loader:它是基于 webpack 的一个的 loader 插件,解析和转换 .vue  文件,提取出其中的逻辑代码 script、样式代码 style、以及 HTML 模版 template,再分别把它们交给对应的 loader 去处理如 style-loader 、 less-loader 等等,核心的作用,就是 提取 。

    2. @vue/compiler-sfc: Vue 2.x 时代,需要 vue-template-compiler 插件处理 .vue 内容为 ast , Vue 3.x 则变成 @vue/compiler-sfc 。

    vue-loader 需要注意

    之前的

    import VueLoaderPlugin  from 'vue-loader/lib/plugin';

    新的

    import { VueLoaderPlugin }  from 'vue-loader';

    VueLoaderPlugin 的职责是将你定义过的其它规则复制并应用到 .vue 文件里相应语言的块。例如,如果你有一条匹配 /\.js$/ 的规则,那么它会应用到 .vue 文件里的 <script> 块。


    转换jsx

    需要安装 https://github.com/vuejs/babel-plugin-jsx

    关于tsx,具体推荐阅读:重拳出击:打造 Vue3.0 + Typescript + TSX 开(乞)发(丐)模式 https://juejin.cn/post/6844904054103998477

    module.exports = function({ types: t }) {
      const buildAttrsCall = (attribs, t) => {
        const props = []
        attribs.forEach(attr => {
          const name = attr.name.name
          const value = attr.value
          !t.isJSXExpressionContainer(value) &&
          props.push(t.objectProperty(t.stringLiteral(name), value))
          t.isJSXExpressionContainer(value) &&
          props.push(t.objectProperty(t.stringLiteral(name), value.expression))
        })
      
        return t.ObjectExpression(props)
      }
      
      const jsxVisitor = {
        JSXElement: {
          exit(path, state) {      
            // 获取 jsx 
            const openingPath = path.get("openingElement")
            const children = t.react.buildChildren(openingPath.parent)
      
            const tagNode = t.react.isCompatTag(openingPath.node.name.name)
              ? t.stringLiteral(openingPath.node.name.name)
              : t.identifier(openingPath.node.name.name)
      
            // 创建 Vue h
            const createElement = t.identifier('h')
            const attrs = buildAttrsCall(openingPath.node.attributes, t)
            // 创建 h(tag,{...attrs}, [chidren])
            const callExpr = t.callExpression(createElement, [tagNode, attrs, t.arrayExpression(children)])
            path.replaceWith(t.inherits(callExpr, path.node))
          }
        },
        JSXAttribute(path) {
          if (t.isJSXElement(path.node.value)) {
            path.node.value = t.jsxExpressionContainer(path.node.value);
          }
        },
        Program: {
          exit(path, state) {
      
            const hasImportedVue = (path) => {
              return path.node.body.filter(p => p.type === 'ImportDeclaration').some(p => p.source.value == 'vue')
            }
            // 注入 h 函数
            if (path.node.start === 0) {
              if (!hasImportedVue(path)) {
                path.node.body.unshift(
                  t.importDeclaration(
                    [t.ImportSpecifier(t.identifier('h'), t.identifier('h'))],
                    t.stringLiteral('vue')
                  )
                )
              } else {
                const vueSource = path.node.body
                  .filter(p => p.type === 'ImportDeclaration')
                  .find(p => p.source.value == 'vue')
                const key = vueSource.specifiers.map(s => s.imported.name)
                if (key.includes('h')) {
                } else {
                  vueSource.specifiers.unshift(t.ImportSpecifier(t.identifier('h'), t.identifier('h')))
                }
              }
            }
          }
        }
      }
      
      return {
        visitor: jsxVisitor,
        inherits:() => {
          return {
            manipulateOptions(opts, parserOpts) {
              parserOpts.plugins.push("jsx")
            }
          }
        }
      }
    }

    这段时间做bk-vision 项目,分别试过 

    vite

    vue-cli

    webpack

    最后还是升级了 bkui-cli,vue2 升级vue3,打包工具还是不要变为好。

    https://github.com/zhoulujun/bkui-cli


    参考文章:

    Vue 3 和 Webpack 5 来了,手动搭建的知识该更新了 https://juejin.cn/post/6921161482663100423

    打造 Vue3.0 + Typescript + TSX 开(乞)发(丐)模式 https://juejin.cn/post/6844904054103998477



    转载本站文章《vue2升级vue3:webpack vue-loader 打包配置》,
    请注明出处:https://www.zhoulujun.cn/html/webfront/ECMAScript/vue3/8852.html