webpack4 构建vue多页工程

webpack4 构建vue多页工程

多页应用开发环境配置

构建开发环境的配置,需要使用到webpack-dev-server,以及webpack4中的mode配置和devServer。

而多页应用的开发则需要使用到html-webpack-plugin这个插件,来构建html

项目的目录结构

-- src
  |-- views
    |-- home
      |-- index.js
      |-- index.html
      |-- index.vue

多页面的entry和页面的构建打包

const setMPA = () => {
  const entrys = {};
    const htmlWebpackPlugins = [];
    
    const entryFiles = glob.sync(path.join(__dirname, "src"));
    
    Object.keys(entryFiles)
      .map((index) => {
        const entry = entryFiles[index];
        
          const match = entry.match(/src\/views\/(.*)\/index\.js/);        
          const pageName = match && match[1];
        
          entrys[pageName] = entry;
          htmlWebpackPlugins(
              new HtmlWebpackPlugin({
                  fileName: `${pageName}.html`,
                    template: path.join(__dirname, `src/views/${pageName}/index.html`),
                    title: `${pageName} title`
                })
            )
      })
    
    return {
      entrys,
        htmlWebpackPlugins
    }
}

webpack.dev.js 开发环境的配置

// webpack.dev.js
const path = require('path');
const glob = require('glob');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const webpack = require('webpack');

const setMPA = () => {
    const entrys = {};
    const htmlWebpackPlugins = [];
    
    const entryFiles = glob.sync(path.join(__dirname, "src"));
    
    Object.keys(entryFiles)
        .map((index) => {
            const entry = entryFiles[index];
        
            const match = entry.match(/src\/views\/(.*)\/index\.js/);        
            const pageName = match && match[1];
        
            entrys[pageName] = entry;
            htmlWebpackPlugins(
                new HtmlWebpackPlugin({
                    fileName: `${pageName}.html`,
                    template: path.join(__dirname, `src/views/${pageName}/index.html`),
                    title: `${pageName} title`
                })
            )
        })
    
    return {
        entrys,
        htmlWebpackPlugins
    }
}

const { entrys, htmlWebpackPlugins } = setMPA();

module.exports = {
    mode: 'development',
    entry: entrys,
    output: {
        filename: 'static/js/[name].js',
        path: path.posix.join(__dirname, 'dist')
    },
    resolve: {
        alias: {
            '@': path.join(__dirname, 'src')
        }
    },
    module: {
        rules: [
            {
                test: /\.js$/,
                use: 'babel-loader'
            },
            {
                test: /\.vue$/,
                use: 'vue-loader'
            },
            {
                test: /\.(png|jpe?g|gif|svg)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            name: 'images/[name].[ext]',
                            limit: 10240
                        }
                    }
                ]
            },
            {
                test: /\.(woff|woff2|eot|ttf|otf)$/,
                use: [
                    {
                        loader: 'file-loader',
                        options: {
                            name: 'fonts/[name].[ext]'
                        }
                    }
                ]
            },
            {
                test: /\.css$/,
                use: [
                    'vue-style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.less$/,
                use: [
                    'vue-style-loader',
                    'css-loader',
                    'less-loader'
                ]
            },
            {
                test: /\.styl(us)?$/,
                use: [
                    'vue-style-loader',
                    'css-loader',
                    'stylue-loader'
                ]
            }
        ]
    },
    plugins: [
        new VueLoaderPlugin(),
        // 热加载
        new webpack.HotModuleReplacementPlugin()
    ].concat(htmlWebpackPlugins),
    devServer: {
        contentBase: path.join(__dirname, 'dist'),
        hot: true
    }
}

babelrc的配置,应用与编译ES的语法

/* .babelrc  */
{
  "presets": [
    "@babel/perset-env"
  ]
}

浏览器的兼容版本,>1%==市场的使用份额大于1%

/* .browserslistrc  */
last 2 version
>1%
IOS 7

正式环境配置

vue的正式环境需要配置mode: production,默认开启UglifyJsPlugin(js代码压缩)。

正式环境的资源hash迭代(hash、chunkhash、contenthash)

使用loader配置资源的提取,针对样式的提取使用mini-css-extract-plugin插件去提取,配合html-webpack-plguin把提取出来的css[chunk]配置进去html中

告警信息人性化,使用插件@soda/friendly-errors-webpack-plugin,

/**
 * font and image 资源  --> hash
 * 从js提取出font和image资源
 */
module.exports = {
  module: {
    rules: [
      {
        test: /\.(png|jpe?g|gif|svg)$/,
        use: [
          {
            loader: 'url-loader',
            options: {
              name: '[name]_[hash:8].[ext]',
              limit: 10240 // 10k https://www.npmjs.com/package/url-loader#limit
            }
          }
        ]
      },
      {
        test: /\.(woff|woff2|eof|ttf|tof)$/,
        use: [
          {
            loader: 'file-loader', // https://www.npmjs.com/package/file-loader#name
            options: {
              name: '[name]_[hash:8].[ext]' // https://www.npmjs.com/package/file-loader#placeholders
            }
          }
        ]
      }
    ]
  }
}

sass 预处理器,配置时需要注意, css 样式处理,使用到contenthash

 /**
 * css --> contenthash 当css的内容没有任何改变,不会随着js[chunkhash]的改变而改变
 * 遵从js的chunkhash
 * 从js中提取出css到文件中
 */
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader'
        ]
      },
      {
        test: /\.(scss|sass)$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          {
            loader: 'sass-loader',
            options: {
              fiber: require('fibers'),
              implemation: require('sass'),
              // indentedSyntax: true
            }
          }
        ]
      },
      {
        test: /\.less$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'less-loader'
        ]
      },
      {
        test: /\.styl(us)?$/,
        use: [
          MiniCssExtractPlugin.loader,
          'css-loader',
          'stylus-loader'
        ]
      }
    ]
  },
  plugins: [
    // https://www.npmjs.com/package/mini-css-extract-plugin
    // 提取出css
    new MiniCssExtractPlugin({
      filename: '[name]_[contenthash:8].css'
    })
  ]
}
const path = requrie('path');
const HtmlWebpackPlguin = require('html-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const VueLoaderPlugin = require('vue-loader/lib/plugin');
const FriendlyErrorsWebpackPlugin = require('@soda/friendly-errors-webpack-plugin');
const webpack = require('webpack');

const setMPA = () => {
  const entrys = {};
    const htmlWebpackPlugins = [];
    
    const entryFiles = glob.sync(path.join(__dirname, "src"));
    
    Object.keys(entryFiles)
      .map((index) => {
        const entry = entryFiles[index];
        
          const match = entry.match(/src\/views\/(.*)\/index\.js/);        
          const pageName = match && match[1];
        
          entrys[pageName] = entry;
          htmlWebpackPlugins(
              new HtmlWebpackPlugin({
                  fileName: `${pageName}.html`,
                    template: path.join(__dirname, `src/views/${pageName}/index.html`),
                    title: `${pageName} title`
                })
            )
      })
    
    return {
      entrys,
        htmlWebpackPlugins
    }
}

const { entrys, htmlWebpackPlguins } = setMPA(); 

module.exports = {
  mode: 'production',
    entry: entrys,
    output: {
      filename: '[name]_[chunkhash:8].js',
        path: path.join(__dirname, 'dist')
    },
    resolve: {
        // 配置文件夹的别名
      alias: {
          '@': path.join(__dirname, 'src')
        }
    },
    module: {
      rules: [
            {
              test: /\.js$/,
                use: 'babel-loader'
            },
            {
              test: /\.vue$/,
                use: [
                    'cache-loader',
                    'vue-loader'
                ]
            },
            {
                test: /\.(png|jpe?g|gif|svg)$/,
                use: [
                  {
                    loader: 'url-loader',
                    options: {
                      name: '[name]_[hash:8].[ext]',
                      limit: 10240 // 10k https://www.npmjs.com/package/url-loader#limit
                    }
                  }
                ]
            },
            {
                test: /\.(woff|woff2|eof|ttf|tof)$/,
                use: [
                    {
                        loader: 'file-loader', // https://www.npmjs.com/package/file-loader#name
                        options: {
                            name: '[name]_[hash:8].[ext]' // https://www.npmjs.com/package/file-loader#placeholders
                        }
                    }
                ]
            },
            {
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                  'css-loader'
                ]
            },
            {
                test: /\.(scss|sass)$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    {
                        loader: 'sass-loader',
                        options: {
                            fiber: require('fibers'),
                            implemation: require('sass'),
                            // indentedSyntax: true
                        }
                    }
                ]
            },
            {
                test: /\.less$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    'less-loader'
                ]
            },
            {
                test: /\.styl(us)?$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    'stylus-loader'
                ]
            }
        ]
    },
    plugins: [
        new VueLoaderPlugin(), // vue-loader15版本之后,需要添加添加此插件
        // 重新打包是清除打包的内容
        new CleanWebpackPlugin(),
        // 提取css
        new MiniCssExtractPlugin({
          filename: '[name]_[contenthash:8].css'
        }),
        // https://www.npmjs.com/package/@soda/friendly-errors-webpack-plugin
        new FriendlyErrorsWebpackPlugin()
    ].concat(htmlWebpackPlugins)
}

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,864评论 6 494
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,175评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,401评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,170评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,276评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,364评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,401评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,179评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,604评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,902评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,070评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,751评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,380评论 3 319
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,077评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,312评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,924评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,957评论 2 351

推荐阅读更多精彩内容