vite-plugin-uni-pages 控制页面是否打包

612 阅读2分钟

vite-plugin-uni-pages 有提供一个钩子方法onBeforeWriteFile,此方法在生成 pages.json 之前调用

pagesGlobConfig

image.png

我们可以在此方法里面访问 uni-pages 插件的上下文,可以看到, pages.json 是通过pagesGlobConfig 和 pageMetaData 和 subPageMetaData 合并生成

在我的 微信小程序 『轻便万物迹』中,分包里面有两个文件夹,现在我不想打包 storage/index 这个页面, 于是我在 route 定义中添加了一个字段 __enable, 用来表示我不想打包此文件, 可以看到, 打包的时候有输出此自定义字段。于是我们可以在读到有此字段的时候,将该对象进行移除,这样,打包后的pages.json 就不会出现此页面。

image.png

image.png

onBeforeWriteFile(ctx) {
  console.log(ctx.pageMetaData);
  console.log(ctx.subPageMetaData);
  ctx.subPageMetaData.forEach((item) = >{
    const newPages = item.pages.filter((route) = >route.__enable === false);
    item.pages = newPages;
  });
}

image.png

可以看到, 构建产物中不包含有__enable: false 字段的页面。

如何控制不同平台的打包

同理, 我们只需要在页面的route对象中声明哪些平台打包,哪些平台不打包,然后通过 UNI_PLATFORM 获取当前正在打包平台名,进行页面过滤。如下图,此时设置了storage/index 这个页面不进行打包(微信平台 mp-weixin),构建产物也不会包含 storage/index 这个页面

const { UNI_PLATFORM } = process.env;


console.log('UNI_PLATFORM -> ', UNI_PLATFORM); // 得到 mp-weixin, h5, app 等

image.png

image.png

如何直接生成完整的pages.json, 但是在pages.json 里面进行条件编译

可以通过json转js然后添加注释实现

image.png

vite-plugin-uni-page 还有一个钩子函数,onBeforeWriteFile 可以在生成pages.json 进行操作。


const parser = require('@babel/parser');
const t = require('@babel/types'); 
const fs = require('fs')
const path = require('path') 
const generate = require('@babel/generator').default;
// 读取 JSON 文件 
const jsonFilePath = path.resolve(__dirname, './pages.json'); 
const jsonContent = fs.readFileSync(jsonFilePath, 'utf-8'); 
// 解析为 JavaScript 对象 
const ast = t.file( t.program([ t.variableDeclaration('const', [ t.variableDeclarator( t.identifier('data'), t.valueToNode(jsonObj) ) ]) ]) );


// 转换 AST
traverse(ast, {
    ObjectExpression(path) {
        
        // console.log(path.node.properties)
      const hasComment = path.node.properties.some(
        prop => 
                prop.key.value === '__comment'
    
      );
  
      if (hasComment) {
        console.log('有注释')
        // 获取父路径的起始和结束位置
        const parentPath = path.parentPath;
        
        // 在前一个token后添加 #ifdef
        path.addComment('leading', '#ifdef A');
        
        // 在后一个token前添加 #endif
        if (t.isVariableDeclarator(parentPath)) {
          parentPath.addComment('trailing', '#endif');
        } else {
          path.addComment('trailing', '#endif');
        }
        
        // 可选:移除 __comment 属性
        path.node.properties = path.node.properties.filter(
          prop => !(t.isObjectProperty(prop) && 
                   t.isIdentifier(prop.key) && 
                   prop.key.name === '__comment')
        );
      }
    }
  });

// 生成代码
const output = generator(ast, {
  comments: true, // 确保保留注释
  retainLines: true,
  concise: false
});

然后将生成的代码转成json

// 解析代码
const ast = parser.parse(code, {
    sourceType: 'module',
    attachComment: true, // 保留注释
});

// 提取对象
const userObject = ast.program.body[0].declarations[0].init;

// 生成 JSON5
const json5 = generate(userObject, {
    comments: true, // 保留注释
    jsonCompatibleStrings: true, // 使用双引号
    concise: false, // 格式化输出
}).code;

// 移除 const code = 和分号
const cleanedJson5 = json5
    .replace(/^const\s+\w+\s*=\s*/, '') // 移除 const code =
    .replace(/;\s*$/, ''); // 移除末尾分号

// 确保键和字符串值都使用双引号
const finalJson5 = cleanedJson5
    .replace(/(\b\w+\b)(?=\s*:)/g, '"$1"') // 确保键带双引号
    .replace(/'([^']*)'/g, '"$1"'); // 将单引号字符串替换为双引号

console.log(finalJson5);