本来我想着用这种方案就可以了,之后又遇到了天坑环节,这次的坑是,使用按需引入的方式,即类似于import { CCard } from "shst-campus";这种形式,如果在本地src中写页面使用的是装饰器的写法的话,是不能正常编译node_modules里的组件的,无论node_modules里的组件是TS还是普通vue组件都会出现这样的情况,这个问题在上边写的博客里写了这就是个大坑,即编译出来的产物是没有css文件以及js文件只有一个Component({}),如果使用的是Vue.extend的写法的话,又是能够正常编译node_modules里的组件,当然本地src编写的组件如果没有使用TS的话是没有问题的,所以现在是有三种解决方案,其实终极大招是写一个webpack loader,这个我在博客中实现过,考虑到通用性才最终没使用,要是实在顶不住了就完善一下直接上loader,至于为什么要写loader而不只是写一个plugin也可以看看博客,天坑。
src中组件使用装饰器写法,引入组件使用真实路径,即类似于import CCard from "shst-campus/lib/c-card/c-card.vue";。
src中组件使用Vue.extend写法,可以使用按需引入,即类似于import { CCard } from "shst-campus";。
src中组件使用这两种写法都可以,然后配置一下uniapp提供的easycom能力,之后可以直接使用组件不需要声明。
如果需要配置组件的按需引入,即类似于import { CCard } from "shst-campus";这种形式,需要修改babel.config.js文件。
// babel.config.js // ... process.UNI_LIBRARIES = process.UNI_LIBRARIES || ["@dcloudio/uni-ui"]; process.UNI_LIBRARIES.push("shst-campus"); process.UNI_LIBRARIES.forEach(libraryName => { plugins.push([ "import", { libraryName: libraryName, customName: name => { return `${libraryName}/lib/${name}/${name}`; }, }, libraryName, ]); }); // ...如果需要使用easycom的引入形式,那么需要配置pages.json。
// pages.json { "easycom": { "autoscan": true, "custom": { "^c-(.*)": "shst-campus/lib/c-$1/c-$1.vue" } }, // ... }这是终极大招解决方案,在后来我抽时间使用parse-imports库完成了一个新的loader,兼容性应该还可以,另外这个库也挺坑的,是个module而没有打包成commonjs,这就导致最后我作为loader使用必须把所有的依赖都打到了一个js里,挺要命的,我准备使用这种方式去解决uniapp组件的坑了,也验证一下库的兼容性,如果使用按需加载的方式上边都可以忽略,只需要安装好依赖并且在vue.config.js中配置好就可以了。
$ yarn add -D uniapp-import-loader // vue.config.js const path = require("path"); module.exports = { configureWebpack: { // ... module: { rules: [ { test: /\.vue$/, loader: "uniapp-import-loader", // import { CCard } from "shst-campus"; // => import CCard from "shst-campus/lib/c-card/c-card"; options: { name: "shst-campus", path: "lib", }, }, ], }, // .. }, }; import parseImports from "parse-imports"; const transformName = (str: string): string => str.replace(/\B([A-Z])/g, "-$1").toLowerCase(); const buildImportStatement = (itemModules: string, itemFrom: string): string => `import ${itemModules} from "${itemFrom}";\n`; export const transform = ( source: string, options: { name: string; path: string; main?: string } ): Promise<string> => { const segmentStartResult = /<script[\s\S]*?>/.exec(source); const scriptEndResult = /<\/script>/.exec(source); if (!segmentStartResult || !scriptEndResult) return Promise.resolve(source); const startIndex = segmentStartResult.index + segmentStartResult[0].length; const endIndex = scriptEndResult.index; const preSegment = source.slice(0, startIndex); const middleSegment = source.slice(startIndex, endIndex); const endSegment = source.slice(endIndex, source.length); return parseImports(middleSegment) .then(allImports => { let segmentStart = 0; let segmentEnd = 0; const target: Array<string> = []; for (const item of allImports) { if (item.isDynamicImport) continue; if (!item.moduleSpecifier.value || item.moduleSpecifier.value !== options.name) { continue; } segmentEnd = item.startIndex; target.push(middleSegment.slice(segmentStart, segmentEnd)); if (item.importClause && item.moduleSpecifier.value) { const parsedImports: Array<string> = []; if (item.importClause.default) { parsedImports.push( buildImportStatement( item.importClause.default, item.moduleSpecifier.value ) ); } item.importClause.named.forEach(v => { parsedImports.push( buildImportStatement( v.binding, // as 会被舍弃 `${v.specifier} as ${v.binding}`, `${options.name}/${options.path}/${transformName(v.specifier)}/${ options.main || transformName(v.specifier) }` ) ); }); target.push(parsedImports.join("")); } segmentStart = item.endIndex; } target.push(middleSegment.slice(segmentStart, middleSegment.length)); return preSegment + target.join("") + endSegment; }) .catch((err: Error) => { console.error("uniapp-import-loader parse error", err); return source; }); }; const { transform } = require("../dist/index"); // loader function module.exports = function (source) { const name = this.query.name; if (!name) return source; const path = this.query.path || "lib"; const main = this.query.main; const done = this.async(); transform(source, { name, path, main }).then(res => { done(null, res); }); }; BLOG https://github.com/WindrunnerMax/EveryDay 参考 https://tslang.baiqian.ltd/ https://cn.eslint.org/docs/rules/ https://www.jianshu.com/p/39261c02c6db https://www.zhihu.com/question/310485097 https://juejin.cn/post/6844904144881319949 https://uniapp.dcloud.net.cn/quickstart-cli https://webpack.docschina.org/api/parser/#import https://v4.webpack.docschina.org/concepts/plugins/ https://cloud.tencent.com/developer/article/1839658 https://jkchao.github.io/typescript-book-chinese/typings/migrating.html