• 使用webpack搭建一个多页应用


     一、前言

      最近需要为公司的活动写8个左右的移动端分享页面,有比较多的页面是公用的,如果用传统的方式来写的话,对于公用的代码抽取,css代码的压缩都是比较麻烦的,所以选择了webpack来搭建一个基本的多页面应用。大概有一下的功能点:

      1.自动添加浏览器前缀到CSS文件中

      2.自动压缩合并 CSS 和 JS 文件

      3.自动清理打包后的dist文件夹

      4.自动生成HTML文件

      5.自动抽取CSS文件

      6.本地开发热更新

      7.HTML模板的导入等

    二、目录结构

      

    三、安装依赖

      autoprefixer:自动为CSS文件添加浏览器前缀

      clean-webpack-plugin:自动清除打包之后的文件

      extract-text-webpack-plugin:CSS文件的单独抽取

      html-loader:导入公用的HTML模板,如下使用

      

      webpack:主要的打包工具

      webpack-dev-server:本地开发的热更新服务器

      webpack-merge:对webpack配置进行合并操作

      hogan:前端的HTML模板

      http-server:http服务器,可以用于访问打包之后的静态资源

    四、具体的package.json文件

    {
      "name": "activityShare",
      "version": "1.0.0",
      "description": "活动分享",
      "main": "index.js",
      "scripts": {
        "dev": "webpack-dev-server --inline --progress --config config/webpack.config.dev.js",
        "build": "webpack -p --config config/webpack.config.prod.js",
        "serve": "http-server dist -p 9999"
      },
      "keywords": [
        "jqery、css、html"
      ],
      "author": "lidongheng",
      "license": "ISC",
      "devDependencies": {
        "autoprefixer": "^7.1.3",
        "clean-webpack-plugin": "^0.1.16",
        "css-loader": "^0.28.7",
        "extract-text-webpack-plugin": "^3.0.0",
        "file-loader": "^1.1.4",
        "html-loader": "^0.5.5",
        "html-webpack-plugin": "^2.30.1",
        "http-server": "^0.10.0",
        "postcss-import": "^11.0.0",
        "postcss-loader": "^2.0.6",
        "postcss-url": "^7.2.1",
        "style-loader": "^0.18.2",
        "url-loader": "^0.5.8",
        "webpack": "^3.5.5",
        "webpack-dev-server": "^2.7.1",
        "webpack-merge": "^4.1.0"
      },
      "dependencies": {
        "hogan": "^1.0.2"
      }
    }

     五、config.js文件包含一些可配置的选项

    module.exports = {
      dev: {
        assetsPublicPath: '/',
        proxyTable: {
          '/api': {
            target: 'http://192.168.9.19:8080',
            changeOrigin: true, //改变源
            pathRewrite: {
              '^/api': ''
            }
          }
        },
        host: '0.0.0.0', // 写成0.0.0.0手机可以通过局域网访问,localhost无法使用手机访问的
        port: 8888,
        autoOpenBrowser: false, // 是否自动打开浏览器
        errorOverlay: true, // 编译错误的时候,在浏览器显示mask
        poll: false,
      },
      prod: {
        assetsPublicPath: '/'
      }
    }

    六、dev.env.js文件和prod.env.js文件,用于定义开发环境和生产环境

    七、webpack基本配置文件webpack.config.base.js

    const path = require("path");
    // 引入插件,自动生成HTML文件的插件
    const HTMLWebpackPlugin = require("html-webpack-plugin");
    // 清理 dist 文件夹
    const CleanWebpackPlugin = require("clean-webpack-plugin")
    // 抽取 css 到单独的文件
    const ExtractTextPlugin = require("extract-text-webpack-plugin");
    // 引入webpack
    const Webpack = require("webpack");
    // 基本配置
    const config = require("./config");
    
    // 解析路径,当前base文件的上一级路径
    function resolve (dir) {
      return path.join(__dirname, '..', dir)
    }
    
    // 计算HtmlWebpackPlugin的参数
    // template是html文件的名称,title是html文件中的title值
    function getHtmlWebpackPluginParams(template,title){
      // 生成的HTML文件放到/dist/view目录下
      return {
        filename: `view/${template}.html`, // 生成的文件放在/dist/view目录下
        template: resolve(`src/view/${template}.html`), // 模板的位置
        title: title, // 设置HTML文件中的title值
        inject: true, // 插入的script标签放在body后面
        hash: true, // 产生hash值
        chunks: [template, 'common'], // script标签中插入的文件为对应html文件的js以及公用的common
      }
    }
    
    var configs = {
      // 多页应用,所以在入口处设置多个入口的JS文件
      entry: {
        "common": ["./src/page/common/index.js"], // 公用的JS文件
        "activitydetail": ["./src/page/activitydetail/index.js"], // 活动详情页面
        "specialdetail": ["./src/page/specialdetail/index.js"], // 活动详情页面
        "signup": ["./src/page/signup/index.js"], // 活动详情报名页面
        "specialsignup": ["./src/page/specialsignup/index.js"], // 专题详情报名页面
        "selectteam": ["./src/page/selectteam/index.js"], // 选择团队的页面
        "createteam": ["./src/page/createteam/index.js"], // 创建团队的页面
        "viewmember": ["./src/page/viewmember/index.js"], // 查看成员的页面
        "download": ["./src/page/download/index.js"], // 下载页面的
      },
      output:{
        filename: 'js/[name].[chunkhash].js', // 【chunkhash】改变内容的时候,hash值就会改变,到时候会强制浏览器获取新的文件
        publicPath: process.env.NODE_ENV === 'prod'
          ? config.build.assetsPublicPath
          : config.dev.assetsPublicPath,
        path: resolve('dist') // 打包的文件放到/dist下
      },
      externals : {
        'jquery' : 'window.jQuery' // 在页面中通过script引入JQ,在page目录下对应的JS文件可以直接使用$符号
      },
      // 加载器
      module: {
        rules: [
          {
            // 对 css 后缀名进行处理
            test:/.css$/,
            // 抽取 css 文件到单独的文件夹
            use: ExtractTextPlugin.extract({
              fallback: "style-loader", // 编译后用什么style-loader来提取css文件
              use: [
                {
                  loader:"css-loader",
                  options:{
                    minimize:true, // 开启 css 压缩
                  }
                },
                {
                  loader:"postcss-loader",
                }
              ]
            })
          },
          {
            test: /.(png|jpe?g|gif|svg)(?.*)?$/,
            loader: 'url-loader',
            options: {
              limit: 100,
              name: path.posix.join('resource/img/[name].[hash:7].[ext]')
            }
          },
          {
            test: /.(mp4|webm|ogg|mp3|wav|flac|aac)(?.*)?$/,
            loader: 'url-loader',
            options: {
              limit: 100,
              name: path.posix.join('resource/media/[name].[hash:7].[ext]')
            }
          },
          {
            test: /.(woff2?|eot|ttf|otf)(?.*)?$/,
            loader: 'url-loader',
            options: {
              limit: 100,
              name: path.posix.join('resource/fonts/[name].[hash:7].[ext]')
            }
          },
          { 
            test: /.string$/,
            loader: 'html-loader'
          }
        ],
      },
      // 别名
      resolve : {
        alias : {
          '@' : resolve('src'),
          node_modules    : resolve('node_modules'),
          utils           : resolve('src/utils'),
          page            : resolve('src/page'),
          service         : resolve('src/service'),
          image           : resolve('src/image')
        }
      },
      plugins:[
        // 抽取公用的JS文件,打包到/dist/js/common.js文件中,也会把common 的chunk打包到/dist/js/common.js中
        new Webpack.optimize.CommonsChunkPlugin({
          name: "common", // 入口中的common chunk
          filename: "js/common.[hash].js"
        }),
        // 自动清理 dist 文件夹
        new CleanWebpackPlugin(["dist"],{
          root: resolve('/'),
          verbose: true,
          dry: false
        }),
        // 将 css 抽取到/dist/css/xxx.css
        new ExtractTextPlugin("css/[name].css"),
        // 自动生成 HTML 插件
        new HTMLWebpackPlugin(getHtmlWebpackPluginParams('activitydetail','活动详情')),
        new HTMLWebpackPlugin(getHtmlWebpackPluginParams('specialdetail','专题详情')),
        new HTMLWebpackPlugin(getHtmlWebpackPluginParams('signup','填写报名单')),
        new HTMLWebpackPlugin(getHtmlWebpackPluginParams('specialsignup','填写报名单')),
        new HTMLWebpackPlugin(getHtmlWebpackPluginParams('selectteam','选择团队')),
        new HTMLWebpackPlugin(getHtmlWebpackPluginParams('createteam','创建团队')),
        new HTMLWebpackPlugin(getHtmlWebpackPluginParams('viewmember','查看成员')),
        new HTMLWebpackPlugin(getHtmlWebpackPluginParams('download','下载青未了'))
      ]
    }
    
    module.exports = configs;

    八、本地开发的基本配置文件webpack.config.dev.js

    const path = require("path");
    // 引入基础配置文件
    const webpackBase = require("./webpack.config.base");
    // 引入 webpack-merge 插件
    const webpackMerge = require("webpack-merge");
    // 引入webpack
    const Webpack = require("webpack");
    // 配置
    const config = require("./config");
    
    // 合并配置文件
    module.exports = webpackMerge(webpackBase,{
      // 配置 webpack-dev-server
      devServer:{
        // 项目根目录
        contentBase: path.join(__dirname, '..', 'dist'),
        clientLogLevel: 'warning',
        hot: true, // 启用 webpack 的模块热替换特性,此特性需要加载plugins:webpack.HotModuleReplacementPlugin
        compress: true, // 开启gzip压缩
        host: config.dev.host,
        progress: true,
        port: config.dev.port,
        open: config.dev.autoOpenBrowser, // 不自动打开浏览器
        publicPath: config.dev.assetsPublicPath,
        // 错误、警告展示设置
        overlay: config.dev.errorOverlay ? 
          { errors: true, warnings: false } : false,
        watchOptions: {
          poll: config.dev.poll
        },
        // 代理
        proxy: config.dev.proxyTable
      },
      plugins: [
        // DefinePlugin 允许创建一个在编译时可以配置的全局常量,可以在JS文件中根据这些定义的变量来定义不同的行为
        new Webpack.DefinePlugin({
          'process.env': require("./dev.env")
        }),
        // 热加载需要配置的插件
        new Webpack.HotModuleReplacementPlugin()
      ]
    })

    九、生产环境打包的webpack.config.prod.js

    // 引入基础配置
    const webpackBase = require("./webpack.config.base");
    // 引入 webpack-merge 插件
    const webpackMerge = require("webpack-merge");
    // 引入 webpack
    const webpack = require("webpack");
    
    // 合并配置文件
    module.exports = webpackMerge(webpackBase,{
      plugins:[
        // DefinePlugin 允许创建一个在编译时可以配置的全局常量,可以在JS文件中根据这些定义的变量来定义不同的行为
        new webpack.DefinePlugin({
          'process.env': require("./prod.env")
        }),
        // 代码压缩
        new webpack.optimize.UglifyJsPlugin({
          // 开启 sourceMap
          sourceMap: true
        })
      ]
    });

     十、主要参考了vue-cli的配置文件结构,有webpack基础的同学应该都能看懂,把主要的配置文件贴出来,有不懂的请留言。还有一点就是没有配置ES6语法的转换,而是直接使用了webpack对js文件的打包,有需要的可以参考vue-cli进行配置。demo

  • 相关阅读:
    错误 com.mysql.cj.exceptions.InvalidConnectionAttributeException: The server time zone value
    mysql数据库
    c程序语言设计
    第二十四天 注解 和 异常
    第二十三天 泛型
    第二十二天 集合
    php tostring用法
    thinkphp批量添加水印
    thinkphp fetchSql
    php钩子是什么意思
  • 原文地址:https://www.cnblogs.com/llcdxh/p/9903977.html
Copyright © 2020-2023  润新知