本次项目的目的,是基于qiankun这个微前端框架写一个vue专用的插件来方便在vue的项目里使用。javascript
起初是想用js写的。但本着如今开发的是一个第三方类库,要考虑通用性。若是用js写,若是使用的项目时typescript的vue项目,就会遇到缺乏类型定义文件的问题。因而采用ts开发。这样申明文件的生成也变得容易一些。css
https://github.com/Hades-li/qiankun-vuehtml
yarn add qiankun-vue
npm install qiankun-vue --save
vue-cli是vue官方的脚手架工具,傻瓜式构建项目,很是好用。但也许它更适合去开发一整套应用,而不是一个小小的第三方库。前端
vue-cli提供了一个官方的构建库方法vue
vue-cli-service build --target lib --name myLib [entry]
这样构建的结果就和官方展现的同样,会同时生成多个js的库文件。而实际在项目引用时,咱们只会用到一个。也就是说,咱们根本不但愿生成一堆咱们不想要的东西。java
放弃使用vue-cli官方自带的方法,剩下的方法就是改写vue.config.js配置来快速实现构建。如下是截取一些重要的代码段讲解node
if (isProd) { config.entry('index').clear().add('./src/index.ts') config.output .filename('index.js') // 输出文件名 .libraryTarget('umd') // 打包类型 .library('QiankunVue') // 全局变量名称 ...... }
在生产环境下,入口文件为src路径下的入口文件。
输出文件设置成index.js,目标类型为umd格式,全局变量为QiankunVuejquery
if (!isProd) { config.entry('index').clear().add('./example/main.ts') }
在开发环境下,目的不是把src的源代码打包输出,而是要运行example中的列子。因此就将入口文件设置成example下的main.ts文件。webpack
// 排除掉Vue config.externals({ vue: { root: 'Vue', commonjs: 'vue', commonjs2: 'vue', amd: 'vue' } })
因为咱们开发的是vue的插件,因此须要将vue排除掉。git
此时,执行yarn run build后,dist目录中就会只生成一个index.js文件,固然,因为我并无屏蔽掉html模板插件,index.html仍是会被生成。
最终我放弃了以上两种vue-cli的构建方式,由于我发现,打包出来的index.js文件大小,高达120+KB。这个大小明显偏大。但我却找不到缘由。
此次改动,目的是作到彻底不依赖vue-cli,开发,生产环境彻底自定义。
build.js-采用函数式方式执行webpack打包。(暂时放弃)
如下是一些重点代码片断
基础配置,包含了生产和开发环境都须要配置
// 预处理.ts文件 { test: /\.ts$/, use: [ 'babel-loader', { loader: 'ts-loader', options: { appendTsSuffixTo: [/\.vue$/], transpileOnly: true } } ], exclude: /node_modules/ }, // 预处理.vue文件 { test: /\.vue$/, loader: 'vue-loader' },
这两段代码主要是预处理.ts文件和.vue文件。
babel-loader是可选的,做用是将es6代码转成es5用于兼容浏览器。现在的chrome,edge,firefox等现代浏览器,对于es6甚至es7支持已经很好了。不加babel-loader,打包文件尺寸能进一步缩小,运行效率还能更高一些,但本着也许还有人用ie的态度,顺手加一下吧。
// 预处理scss { test: /\.s[ac]ss$/, use: [ env.NODE_ENV !== 'production' ? 'vue-style-loader' : MiniCssExtractPlugin.loader, 'css-loader', 'sass-loader' ] }, // 预处理css { test: /\.css$/, use: [ env.NODE_ENV !== 'production' ? 'vue-style-loader' : MiniCssExtractPlugin.loader, 'css-loader' ] },
预处理scss,和css样式。其实在vue-cli构建出来的项目中,还能支持less,stylu另外两种预编译样式文件,但咱们如今是自定义webpack配置,本着,用到什么就配什么原则,只须要知足本身的需求便可。
// 预处理图片 { test: /\.(png|jpe?g|gif|webp)(\?.*)?$/, loader: 'url-loader', options: { limit: 4096, esModule: false, // 5.0版本以上要加 fallback: { loader: 'file-loader', options: { name: 'img/[name].[hash:8].[ext]' } } } }
预处理图片,这里要着重说一下这个配置项的坑。此配置用于解析图片/文件路径,以及对图片进行base64转换。起初,我是直接用vue-cli审查出了一个webpack配置文件,将这部分拷贝过来,和以上代码相比,仅仅是没有esModule: false这个参数。运行的结果是,全部图片不展现,查看图片路径是这样<img src=[object module]>
。因而加上esModule:false就ok了。
以上缘由是因为vue-loader在对.vue文件解析时,
<img src="../image.png">
标签会被编译成
createElement('img', { attrs: { src: require('../image.png') // commonJS语法导入函数 如今这是一个模块的请求了 } })
require是commonJS规范的导入函数。而url-loader默认是识别es6的导入语法,即import。因而,最终转换出的代码就没法正常显示图片。esModule: false就是启用commonJS引入方式。
那为何vue-cli构建出来的项目则不须要配置这个参数?
由于vue-cli所采用的url-loader版本号还停留在2.x.x。而最新版本已经到了4.x.x。旧版本url-loader是没有这个限制机制。新版url-loader是鼓励采用es6的标准规范来引入文件。commonJs是nodejs的规范。
plugins: [ new VueLoaderPlugin(), // 配合vue-loader new ForkTsCheckerWebpackPlugin(), // 将ts-loader类型检查跑在一个独立线程加速编译 new webpack.DefinePlugin({ 'process.env': { NODE_ENV: '"' + env.NODE_ENV + '"', BASE_URL: '"/"' } }), // 给浏览器代码中添加全局变量 new FriendlyErrorsPlugin(), // 友好的错误提示 new MiniCssExtractPlugin(), // css提取 new CaseSensitivePathsPlugin() // 严格路径大小写 ]
以上这些插件基本都是看着vue-cli审查加入的。有的能够不加,但加了,对于开发都是有极大帮助的。
生产环境下的配置。
module.exports = merge(baseConf({ NODE_ENV: env }), { mode: env, entry: './src/index.ts', output: { path: resolve('dist'), filename: 'index.js', publicPath: '/', chunkFilename: 'js/[name].[contenthash:8].js', libraryTarget: 'umd', library: 'QiankunVue' }, externals: { vue: { root: 'Vue', commonjs: 'vue', commonjs2: 'vue', amd: 'vue' } }, plugins: [ // 清理dist文件夹 new CleanWebpackPlugin() ] })
生产环境配置较为简单,首先经过webpack-merge
这个插件将webpack.config.base.js的配置合并过来,添加entry,和output的配置项,而且用cleanwebpackPlugin插件清理一下dist目录,就能够一键打包了。
开发环境下的配置。
entry: './example/main.ts', output: { path: resolve('dist'), filename: 'app.js', publicPath: '/' }, devServer: { contentBase: resolve('dist'), port: 8080, hot: true, progress: true, // 0-100%的进度提示 quiet: true // 去掉一堆告警信息 }, devtool: 'eval-source-map',
开发环境,一样合并webpack.config.base.js,改写一下entry指向example/main.ts。
配置一下开发服务器devServer,切记,别忘了安装webpack-dev-server
这个包。
plugins: [ new webpack.HotModuleReplacementPlugin(), // 支持热模块替换 new HtmlWebpackPlugin({ title: 'qiankun', template: resolve('public/index.html'), favicon: resolve('public/favicon.ico') }), // 配置index.html模板 new CopyWebpackPlugin([ { from: resolve('public'), to: resolve('dist'), toType: 'dir', ignore: ['index.html'] } ]) // 拷贝插件,用于拷贝一些不参与打包的静态资源至dist目录 ]
这些都是开发模式下必要的插件
以上的这些webpack配置,比起vue-cli提供的要少不少,好比咱们甚至都没有针对.js文件编译loader配置项,由于咱们的项目中纯玩ts。实际用vue-cli构建的ts项目是能够进行js,ts混合开发的。但纯手写webpack的目的,就是只配本身须要的。
本期重点介绍webpack配置,这也是此项目里难点之一,耗时费力。
开发一个标准的js库,无论你是用js开发仍是ts,现在,都是要给本身的库写ts的类型申明文件。像相似lodash,jquery这些著名的库,早期都是没有申明文件。致使若是用于ts项目开发,类型检测机制就没法进行(早期没有typescript)。但如今,这些库都已经将类型申明补充进来了。
类型申明能够手写,但太费事。最好固然是自动生成。
按照官方说法,在tsconfig.js中配置了declaration: true
的属性时,就能够自动生成。但实际是没有任何反应。固然,你若是直接用tsc --declaration命令行编译,则能够生成,目前这是个遗留问题。若是有大神知道解决方法忘指教。