美文网首页
基于webpack5+vue3+ts的chrome插件开发环境搭

基于webpack5+vue3+ts的chrome插件开发环境搭

作者: hello_小丁同学 | 来源:发表于2021-07-19 10:08 被阅读0次

    tips: 本框架目前支持options和popup页面打包,background.js、content.js和devtool打包目前暂未适配。

    背景

    在开发完baymax插件之后,把常用的二维码、网址链接也加到这个插件里了,以后还肯能会添加更多功能,就让这个插件变得臃肿。便想着代码重构,把它做成可配置的,可以通过options页面配置想要的模块在popup中展示。既然要重构,便采用了比较新的webpack5、vue3、ts技术栈。

    chrome插件开发和普通web开发的差异

    差异有以下几点:

    1. chrome插件开发环境是多页面的,需要独立配置options、popup等页面
    const chromeName = ['popup', 'options']
    let entryObj = {}
    chromeName.forEach(name => {
        entryObj[name] = path.resolve(__dirname, `src/${name}/main.ts`)
    })
    
    const htmlWebpackPluginList = chromeName.map(name => {
        return new HtmlWebpackPlugin({
            template: 'index.html',
            filename: `${name}.html`,
            chunks: [name]
        })
    })
    const config ={
        entry: entryObj,
        plugins: [
            ...htmlWebpackPluginList,
       ]
    }
    
    1. 另外manifest.json、静态资源也需要复制到最终输出的目录中
    const fileCopyList = [
        {
            from: path.resolve('src/manifest.json'),
            to: `${path.resolve('dist')}/manifest.json`
        },
        {
            from: path.resolve('src/assets/logo.png'),
            to: `${path.resolve('dist')}/img/logo.png`
        },
        {
            from: path.resolve('src/background/background.js'),
            to: `${path.resolve('dist')}/js/background.js`
        },
        {
            from: path.resolve('src/content/content.js'),
            to: `${path.resolve('dist')}/js/content.js`
        },
    ]
    {
    new CopyWebpackPlugin({patterns: fileCopyList}),
    }
    
    1. 热更新的差异,普通web开发输出的资源是在内存中,chrome插件开发则要输出到磁盘中,另外需要设置disableHostCheck: true,跳过host检查,open: false,避免自动打开网页。
        devServer: {
            contentBase: false,
            // publicPath: './dist',
            hot: true,
            port: 8080,
            open: false,
            lazy: false,
            // hotOnly: true,
            disableHostCheck: true,
            compress: true,
            overlay: true,
            writeToDisk: true,
        },
    

    完整的webpack配置如下:

    const path = require('path');
    const { HotModuleReplacementPlugin, IgnorePlugin } = require('webpack');
    const { CleanWebpackPlugin } = require('clean-webpack-plugin');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const { VueLoaderPlugin } = require('vue-loader');
    const ForkTsCheckerWebpackPlugin = require('fork-ts-checker-webpack-plugin');
    const CopyWebpackPlugin = require('copy-webpack-plugin')
    
    const chromeName = ['popup', 'options']
    
    const fileCopyList = [
        {
            from: path.resolve('src/manifest.json'),
            to: `${path.resolve('dist')}/manifest.json`
        },
        {
            from: path.resolve('src/assets/logo.png'),
            to: `${path.resolve('dist')}/img/logo.png`
        },
        {
            from: path.resolve('src/background/background.js'),
            to: `${path.resolve('dist')}/js/background.js`
        },
        {
            from: path.resolve('src/content/content.js'),
            to: `${path.resolve('dist')}/js/content.js`
        },
    ]
    
    let entryObj = {}
    chromeName.forEach(name => {
        entryObj[name] = path.resolve(__dirname, `src/${name}/main.ts`)
    })
    
    const htmlWebpackPluginList = chromeName.map(name => {
        return new HtmlWebpackPlugin({
            template: 'index.html',
            filename: `${name}.html`,
            chunks: [name]
        })
    })
    
    const config = {
        mode: 'development',
        entry: entryObj,
        output: {
            filename: 'js/[name].js',
            path: path.resolve(__dirname, 'dist')
        },
        devServer: {
            contentBase: false,
            // publicPath: './dist',
            hot: true,
            port: 8080,
            open: false,
            lazy: false,
            // hotOnly: true,
            disableHostCheck: true,
            compress: true,
            overlay: true,
            writeToDisk: true,
        },
        watchOptions: {
            ignored: /node_modules/
        },
        plugins: [
            new CleanWebpackPlugin(),
            ...htmlWebpackPluginList,
            new IgnorePlugin(/^\.\/locale$/, /moment$/),
            new HotModuleReplacementPlugin(),
            new VueLoaderPlugin(),
            new ForkTsCheckerWebpackPlugin({ // ? fork一个进程进行检查,并设置async为false,将错误信息反馈给webpack
                async: false,
            }),
            new CopyWebpackPlugin({patterns: fileCopyList}),
        ],
        module: {
            rules: [
                // babel使用runtime,避免将不需要的代码注入
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    use: [{
                        loader: 'babel-loader',
                        options: {
                            // cacheDirectory: true,
                            presets: ['@babel/preset-env'],
                            plugins: [
                                '@babel/plugin-transform-runtime',
                                ['import', {
                                    "libraryName": "antd",
                                    "style": true,   // or 'css'
                                }, 'antd']
                            ]
                        }
                    }],
                },
                {
                    test: /\.ts$/,
                    exclude: /node_modules/,
                    use: [
                        {
                            loader: 'ts-loader',
                            options: {
                                // 指定特定的ts编译配置,为了区分脚本的ts配置
                                configFile: path.resolve(__dirname, './tsconfig.json'),
                                appendTsSuffixTo: [/\.vue$/],
                                transpileOnly: true,
                            }
                        }
                    ]
                },
                {
                    test: /\.vue$/,
                    loader: 'vue-loader'
                },
                {
                    test: /\.css$/,
                    use: ['style-loader', 'css-loader']
                },
                {
                    test: /\.less$/,
                    use: ['style-loader', 'css-loader',
                        {
                            loader: 'less-loader',
                            options: {
                                lessOptions: {
                                    javascriptEnabled: true,
                                }
                            }
                        }],
                }
            ]
        },
        resolve: {
            extensions: ['.js','.vue', '.json', '.ts']
        },
    };
    
    
    module.exports = (env) => {
        console.log(`当前执行${env.mode}模式`);
        return config;
    }
    
    

    package.json配置:

    {
      "name": "baymax-vue3",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "dev": "webpack-dev-server --config webpack.dev.config.js --env.mode development --watch --profile",
        "prod": "webpack --config webpack.prod.config.js --env.mode product"
      },
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "@babel/core": "^7.14.6",
        "@babel/plugin-transform-runtime": "^7.14.5",
        "@babel/preset-env": "^7.14.7",
        "@vue/compiler-sfc": "^3.1.4",
        "babel-loader": "^8.2.2",
        "babel-plugin-import": "^1.13.3",
        "clean-webpack-plugin": "^4.0.0-alpha.0",
        "copy-webpack-plugin": "^9.0.1",
        "css-loader": "^6.0.0",
        "fork-ts-checker-webpack-plugin": "^6.2.12",
        "html-webpack-plugin": "^5.3.2",
        "less": "^4.1.1",
        "less-loader": "^10.0.1",
        "style-loader": "^3.1.0",
        "ts-loader": "^9.2.3",
        "typescript": "^4.3.5",
        "vue-loader": "^16.3.0",
        "webpack": "^5.44.0",
        "webpack-cli": "^3.3.12",
        "webpack-dev-server": "^3.11.2"
      },
      "dependencies": {
        "@babel/runtime": "^7.14.6",
        "ant-design-vue": "^2.2.2",
        "vue": "^3.1.4",
        "vuex": "^4.0.2"
      }
    }
    

    tsconfig.json配置

    {
      "compilerOptions": {
        // "esModuleInterop": true,
        "incremental": true, // 增量编译
        "allowJs": true,
        "target": "esnext",
        "module": "esnext",
        // 这样就可以对 `this` 上的数据属性进行更严格的推断`
        "strict": true,
        "moduleResolution": "node",
        "resolveJsonModule": true,
      },
      "exclude": [
        "node_modules"
      ]
    }
    

    目录结构:


    image.png

    相关文章

      网友评论

          本文标题:基于webpack5+vue3+ts的chrome插件开发环境搭

          本文链接:https://www.haomeiwen.com/subject/rekzpltx.html