美文网首页
webpack多页应用配置

webpack多页应用配置

作者: 风向应该可以决定发型吧 | 来源:发表于2019-11-15 19:47 被阅读0次

    说明: 网上很多教程,大各种各样的内容都有,自己研究的时候查了很多文档,出现了一些错误都一一记录下来.并且配置文件没有任何的封装,旨在能提炼出最关键的内容.

    环境

    webpack: 4
    

    1. 要用到的插件:

    html-webpack-plugin // 用于根据html模板生成页面
    clean-webpack-plugin // 用于清除dist目录下的代码
    extract-text-webpack-plugin // 用于提取出css到单个或者多个单独文件中
    

    2. 项目目录

     ProjectName
        ├ ─ dist  // 准备发布代码时build出来的文件在这里(需在webpack.config.js中配置)
        ├ ─ node_modules
        ├ ─ src
               ├ ─ css
                      ├ ─ index.css
                      ├ ─ about.css
               ├ ─ js
                      ├ ─ index.js
                      ├ ─ about.js
               ├ ─ pages
                      ├ ─ index.html
                      ├ ─ about.html
        ├ ─ favicon.ico // 可有可无,因为我项目里放了,就写在这里了
        ├ ─ package.json
        ├ ─ webpack.config.js // webpack 配置文件
    

    3. 开始

    1. 创建项目
    mkdir mutile-page-demo 
    cd mutil-page-demo
    npm init -y
    
    2. 创建目录
    mkdir src
    mkdir src/css
    mkdir src/js
    
    3. 创建文件(完全可以使用IDE创建出这个目录结构,不一定要使用命令行,我这里只是为了展示起来更直观)
    # 注意使用git-bash或Cmder命令行工具,windows命令行中是没有 touch命令的
    touch webpack.config.js 
    touch ./src/pages/index.html
    touch ./src/pages/about.html
    touch ./src/css/about.css
    touch ./src/css/about.css
    touch ./src/js/about.js
    touch ./src/js/about.js
    
    4. 下面罗列文件内容,可以自己随便写,也可以copy下面的内容.

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>index</title>
      <link rel="stylesheet" href="../css/index.css">
      <script src="../js/index.js">
      </script>
    </head>
    <body>
      <div class="title">this is index.html</div>
      <a href="about.html">about</a>
    </body>
    </html>
    

    about.html

    <!DOCTYPE html>
    <html lang="en">
    
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>about</title>
      <link rel="stylesheet" href="../css/about.css">
    </head>
    
    <body>
      <div class="title">this is about.html</div>
      <a href="index.html">index</a>
    </body>
    
    </html>
    

    index.js

    window.onload = function () {
      var title = 'index'
      var p = document.createElement('p')
      p.innerText = 'append tag p from index.js!'
      document.body.appendChild(p)
    }
    

    about.js

    window.onload = function () {
      var p = document.createElement('p')
      p.innerText = 'append tag p from about.js!'
      document.body.appendChild(p)
    }
    

    index.css

    .title {
      color: red;
    }
    

    about.css

    .title {
      color: blue;
    }
    
    5. 编写配置文件: webpack.config.js

    module.exports 中有几个关键点:

    • entry: 入口文件: 简单理解为,webpack从这里开始编译,接受的参数类型
      • 字符串,如: entry: 'index.js' # 配置单页应用

      • 数组, 如: entry: ['index.js', 'about.js']

      • 对象(我使用这种方式): 如:

    entry: {
        index: path.resolve(__dirname, 'src/js/index.js'),
        about: path.resolve(__dirname, 'src/js/about.js')
      },
    
    • output: 用于设置输出文件的配置(build)
    • module: 相关loader配置
    • plugins: 相关插件配置
    • devServer: 开发环境启动的服务,hot reload 在这里配置

    直接贴部分代码并说明

    entry

    entry: {
        index: path.resolve(__dirname, 'src/js/index.js'), // 获得目标文件的绝对路径
        about: path.resolve(__dirname, 'src/js/about.js')
      },
    

    output

    path: path.resolve(__dirname, 'dist'), // 将build结果输出到 project 的 dist/ 目录下
    filename: 'js/[name]-[hash].bundle.js' // 将js文件输出到 js/ 目录下 
    

    module.rules 配置

    module: {
        rules: [{
          test: /\.css$/,
          use: ['style-loader', 'css-loader'] 
        }]
      },
    

    注意 style-loader要卸载css-loader的前面,否测会报错

    image.png

    plugins配置

    new htmlWebpackPlugin({
      filename: 'index.html',  // 生成的html文件名称,可以同时指定输出的路径,如: /pages/index.html,将被输出到 /dist/pages/index.html
      template: path.resolve(__dirname, 'src/pages/index.html'), // 模板位置
      inject: 'head', // 控制webpack把js文件append到html的head还是body中,默认是body
      title: 'index', // 传递title到生成的html中
      chunks: ['index'], // 设置生成的html中要引入哪些js文件: chunk名称需要和entry中的属性保持一致,多个js以数组方式配置,如 chunks: ['index', 'about']
      // favicon: path.resolve('favicon.ico'), // 设置hmtl的shortcut icon
      // minify: { // 启用压缩功能
      //   removeComments: true,  //删除注释
      //   collapseWhitespace: true //删除空格
      // }
    }),
    new htmlWebpackPlugin({
      filename: 'about.html',
      template: path.resolve(__dirname, 'src/pages/index.html'),
      inject: 'head',
      title: 'about',
      chunks: ['about']
    }),
    ......如果有多个页面需要也这样写
    

    devServer

    {
         // 注意设置了此属性将导致hot失效
         // 并且会导致js中通过import引入css出现一些问题
        // openPage: 'src/pages/index.html',
    
        open: true, // 自动打开浏览器并访问页面
        inline: true, // 内联模式实时刷新,推荐方式
        hot: false, // 热更新,注意当设置为true时,会导致热更新失败,浏览器不再刷新代码,原因不知
        port: 9527,
        host: 'localhost',
        // compress: true, // 启用压缩,会增加服务器端和客户端的负载
      }
    
    6 添加运行代码

    在package.json的 scripts 中添加2行代码,保存!

    "start": "webpack-dev-server --config webpack.config.js" 
    "build": "webpack --config webpack.config.js",
    

    在命令行中执行: npm start

    image.png

    查看浏览器页面中,发现样式并没有生效
    因为webpack中没有像entry那样的节点来单独配置css的输出,所以html中默认的link并不能让webpack帮我们把css文件一起打包

    解决方法: 在index.js中import需要的css, webpack的思想是一切皆为模块,所以css也可以通过import引入.

    修改index.js为:

    import '../css/index.css' # 新增加的一行
    window.onload = function () {
      var p = document.createElement('p')
      p.innerText = 'append tag p from index.js!'
      document.body.appendChild(p)
    }
    

    保存后查看浏览器发现样式生效了


    image.png

    然后我们在命令行中执行一下: npm run build
    查看procjet中生成了dist目录:

    image.png
    发现我们预想的css目录没有出现,但是如果查看 由index.js生成的文件末尾(需要格式化一下代码,也可以直接搜索名称为title的样式),会看到 index.css中的代码
    image.png

    原来webpack把我们的css代码编译到了js中,在打开页面的时候,样式会被追加到html的style标签中.
    为了解决这个问题,使用 extract-text-webpack-plugin 插件抽取css

    7 使用 extract-text-webpack-plugin 插件抽取css

    如果你还未安装此插件,需要安装

    cnpm i -D extract-text-webpack-plugin
    

    在webpack.config.js中,添加以下代码

    const ExtractTextPlugin = require("extract-text-webpack-plugin");
    

    将 modules.exports rules中 css的配置更改掉:

    use: ExtractTextPlugin.extract({
     fallback: "style-loader",
     use: "css-loader"
    })
    
    


    image.png

    改为


    image.png

    在plugins节点中,添加一行

     new ExtractTextPlugin({
        filename: 'css/[name].css'
     })
    

    再次执行 npm run build,得到正确的输出

    image.png
    8. 如果你仔细看,会发现当你修改过js文件后,再执行 npm run build,会发现 /dist/js 中出现了多个带有不同hash串的 相同文件名. 比如: index-85eb01adecdeb439d2cb.bundle.js 和 index-fe758ed5a5b3da38a76e.bundle.js,见下图.
    image.png

    这是因为hash的原因,webpack在打包的时候会计算文件的hash值,如果文件被改动,那么整个编译出来的hash串也都会变化.(可以通过下面扩展中说明的chunkhash 和 contenthash来优化output节点中的 filename)
    这时,最简单的方法就是build之前先清空掉dist,所以使用了 clean-webpack-plugin 插件

    在 webpack.config.js 中加入一行

    const {
      CleanWebpackPlugin
    } = require('clean-webpack-plugin'); // 文件夹清除工具
    

    并且在plugins节点中增加:

    new CleanWebpackPlugin(), // 清空dist文件夹
    
    image.png

    扩展:

    hash和chunkhash、contenthash区别
    hash: hash是跟整个项目的构建相关,只要项目里有文件更改,整个项目构建的hash值都会更改,并且全部文件都共用相同的hash值
    chunkhash: chunkhash根据不同的入口文件(Entry)进行依赖文件解析、构建对应的chunk,生成对应的哈希值。我们在生产环境里把一些公共库和程序入口文件区分开,单独打包构建,接着我们采用chunkhash的方式生成哈希值,那么只要我们不改动公共库的代码,就可以保证其哈希值不会受影响。
    contenthash: 假设index.js引用了index.css,若使用chunkhash的话,只要js改变,那么css也会被重新构建。如何防止css被重新构建呢?
    可以使用extract-text-webpack-plugin提取单独的css文件并使用contenthash,contenthash 只要文件内容不变,那么不会重复构建。

    总结:

    1. 通过entry对象方式配置多入口
    2. 通过output将js输出到指定目录
    3. 通过html-webpack-plugin,指定输出多个index.html 页面
    4. 通过webpack-dev-server开启本地服务
    5. 通过import 'xxx.css' 配合 extract-text-webpack-plugin 插件修改,rules配置和在plugins中添加下面代码实现css抽离到单个文件或多个文件
    new ExtractTextPlugin({ // 抽离到多个页面
        filename: 'css/[name].css'
      }) 
    
    new ExtractTextPlugin("styles.css") // 抽离到单个页面
    

    遇到的问题:

    1. 执行npm run build时报错
    Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead
    

    原因: extract-text-webpack-plugin还不能支持webpack4.0.0以上的版本。
    解决方法: 安装最新版本

    cnpm install --save-dev extract-text-webpack-plugin@next
    

    发现的问题

    1. 如果plugins中配置了多个目录,并且有多个目录下同时拥有index.html,如果没有配置对应的index.html输出到指定的目录中,那么当npm start时自动打开的首页面是 new htmlWebpackPlugin()写在最后的一个页面,
      比如:
    new htmlWebpackPlugin({
          template: path.resolve(__dirname, 'src/pages/zh-CN/index.html'),
          inject: 'head',
          title: 'index',
          chunks: ['index'],
          favicon: path.resolve('favicon.ico'),
          filename: 'index.html',
        }),
    new htmlWebpackPlugin({
          template: path.resolve(__dirname, 'src/pages/zh-TW/index.html'),
          inject: 'head',
          title: 'index',
          chunks: ['index'],
          favicon: path.resolve('favicon.ico'),
          filename: 'index.html',
        }),
    new htmlWebpackPlugin({
          template: path.resolve(__dirname, 'src/pages/test/index.html'),
          inject: 'head',
          title: 'index',
          chunks: ['index'],
          favicon: path.resolve('favicon.ico'),
          filename: 'index.html',
        }),
    

    原因大概是,最后根据src/pages/test/index.html生成的index.html把前面的覆盖了.

    1. 当给devServer设置了 openPage: 'src/pages/zh-CN/index.html' 时,会导致hot失效,并且js中通过import引入css也会出现一些问题,并在浏览器中报错.

    参考文档:

    1. https://blog.csdn.net/joyce_lcy/article/details/78627268#1-%E5%AE%89%E8%A3%85%E6%8F%92%E4%BB%B6
    2. https://segmentfault.com/a/1190000011434481?utm_source=tag-newest

    相关文章

      网友评论

          本文标题:webpack多页应用配置

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