zoukankan      html  css  js  c++  java
  • webpack最佳入门实践系列(5)

    9.路径相关

    原来我们打包的东西都存放到了dist目录下,并没有进行分类存储,乱成一团,这一节我们就要处理一下打包的路径,让打包后的目录看起来更加优雅

    9.1.代码准备

    我们先建立起这样一个目录结构

    .
    ├── node_modules
    ├── src
    |   ├── assets
    |       └── css
    |           └── index.css
    |       └── img
    |            └── noding.jpg
    |       └── js
    |            └── index.js
    |   └── index.html
    ├── .babelrc
    ├── package-lock.json
    ├── package.json
    ├── webpack.config.js
    └── dist
    

      

    你只需要把前面我们写的代码copy一份,然后删除掉dist里面的东西并且在src下新建assets文件夹来装css和img就可以了

    我们在src/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>Document</title>
    </head>
    <body>
        <div id="box"></div>
        <i class="fa fa-bath" aria-hidden="true"></i>
        <i class="fa fa-envelope-open" aria-hidden="true"></i>
        <i class="fa fa-microchip" aria-hidden="true"></i>
        <i class="fa fa-user-circle-o" aria-hidden="true"></i>
    </body>
    </html>
    

      

    接下来在assets/js/index.js中输入下面代码

    // 引入icon图标字体
    import "font-awesome/css/font-awesome.css"
    
    // 引入图片
    
    import imgSrc from '../img/nodeing.jpg'
    
    // 把图片插入到html网页中
    
    document.getElementById("box").innerHTML = '<img src="'+imgSrc+'" />'
    

      

    然后去webpack.config.js中去修改一下入口文件位置

    接下来,我们去测试一下打包效果

    npm run dev
    

      

    所有文件都打包到dist目录下,到此,我们这小节准备工作已经完成,接下来,我们需要去优化webpack配置,让打包出来的文件不那么混乱

    9.2.webpack配置

    9.2.1.把js文件分类

    我们希望打包出来的文件也像src目录一样能够分门别类的存放,首先,我们把js单独放进assets/js文件夹下,这时我们需要修改webpack配置文件,把输出目录改掉

    output: {
        path: path.resolve(__dirname, 'dist/assets'),
        filename: 'js/app.js'
    },
    

      

    运行npm run dev 查看效果,发现dist目录下多出了一个assets文件,并且已经建立好了js文件夹,app.js也被放进来了,但是,原来打包出来的那些文件还在,这时候,dist目录就更乱了,我们希望每次打包生成的文件都是最新的,得手动去删除上次打包出来的文件,像这种手动删除dist目录的操作,我们可以交给webpack相关插件来完成,这个插件叫clean-webpack-plugin

    安装clean-webpack-plugin插件

    npm install clean-webpack-plugin --save
    

      

    修改webpack配置文件,引入clean-webpack-plugin插件

    const path = require("path")
    
    
    const HtmlWebpackPlugin = require("html-webpack-plugin")
    // 引入clean-webpack-plugin插件
    const CleanWebpackPlugin = require("clean-webpack-plugin")
    
    module.exports = {
        entry: "./src/assets/js/index.js",
        output: {
            path: path.resolve(__dirname, 'dist/assets'),
            filename: 'js/app.js'
        },
        plugins: [
            new HtmlWebpackPlugin({
                template: './src/index.html',
                filename: 'index.html'
            }),
            // 使用插件,设置需要清除的目录
            new CleanWebpackPlugin(['dist'])
        ],
        devServer: {
            open: true
        },
        module: {
            rules: [
                {
                    test: /.js$/,
                    use:['babel-loader'],
                    exclude: path.resolve(__dirname, 'node_modules')
                },
                {
                    test: /.css$/,
                    use: ['style-loader', 'css-loader']
                },
                // 处理文字
                {
                    test: /.(eot|svg|ttf|woff|woff2)$/,
                    use: 'file-loader'
                },
                {
                    test: /.(jpg|png|gif|webp|bmp)$/,
                    use: [{
                        loader: 'url-loader',
                        options: {
                            limit: 10240
                        }
                    }]
                }
            ]
        }
    
    }
    

      

    这个时候你会发现,每次运行npm run dev,这个插件就会先把上次的dist目录删除,然后再新建一个dist目录,把新打包的文件放里面

    以上步骤,我们把js文件放到了assets/js目录下,但随之而来的就是,所有的文件都被打包到assets这个目录下了,我们不希望index.html这个文件也被打包进assets目录下,而是像在src目录下一样,它们应该是同级的,所以我们需要修改一下 index.html被输出的路径

     plugins: [
        new HtmlWebpackPlugin({
            template: './src/index.html',
            // 这里表示往外回退一层
            filename: '../index.html'
        }),
        new CleanWebpackPlugin(['dist'])
    ],
    

      

    9.2.2.把字体文件分类

    修改webpack配置文件,给字体文件增加输出规则

     // 处理文字
    {
        test: /.(eot|svg|ttf|woff|woff2)$/,
        use: [{
            loader: "file-loader",
            options: {
                name: 'fonts/[name]_[hash:4].[ext]'
            }
        }]
    },
    

      

    其中,[name]、[hash]、[ext]都是可变的,name表示原来的文件名字,hash表示生成的hash值,hash:4表示可以限定hash字符串的位数,ext表示原来文件的扩展名(文件后缀)

    9.2.3.把图片文件分类

    修改webpack配置文件,给图片文件增加输出规则

     {
        test: /.(jpg|png|gif|webp|bmp)$/,
        use: [{
            loader: 'url-loader',
            options: {
                limit: 10240,
                name: 'img/[name]_[hash:4].[ext]'
            }
        }]
    }
    

      

    因为,ulr-loader是对file-loader的封装,其中的[name]、[hash]、[ext]表示的意思和file-loader中表示的意思是一样的

    9.2.4.把css文件分类

    css文件是打包进js文件的,如果需要单独打包出来,需要安装另一个插件,extract-text-webpack-plugin

    npm install extract-text-webpack-plugin --save-dev
    

      

    这个插件的使用规则和其他plugin差不多,首先需要引入插件

    const ExtractTextWebpackPlugin = require("extract-text-webpack-plugin")
    

      

    其次,是需要实例化对象,并且传入配置项,然后将实例化出来的这个对象加入到plugins选项中

    const extractcss = new ExtractTextWebpackPlugin({
        //打包输出的路径
        filename:  'assets/css/index.css'
    })
    plugins: [
            new HtmlWebpackPlugin({
                template: './src/index.html',
                filename: './index.html'
            }),
            new CleanWebpackPlugin(['dist']),
            // 这里是前面实例化得到的对象
            extractcss
        ],
    

      

    最后,需要修改css输出规则

    {
        test: /.css$/,
        use: extractcss.extract({
            fallback:'style-loader',
            use:['css-loader']
        })
    },
    

      

    9.2.5.修正url地址

    当我们把各种类型的文件分类好以后,运行打包出来的index.html,发现图片、字体、css等的路径是不正确的,没办法正常工作,这个时候,我们需要用output配置项下的 publicPath来修正一下

    output: {
            path: path.resolve(__dirname, 'dist/assets'),
            filename: 'js/app.js',
            publicPath: 'assets/'
        },
    

      

    其中,publicPath设置的是所有静态资源的基础目录,要快速理解它,可以记住下面的公式

    静态资源最终访问路径 = output.publicPath + 资源loader或插件等配置路径
    

      

    举例说明,我们在各种loader中设置的路径如下:

    // css输出路径
    name: 'css/[name]_[hash:4].[ext]'
    // 图片输出路径
    name: 'img/[name]_[hash:4].[ext]'
    // 字体文件输出路径
    name: 'fonts/[name]_[hash:4].[ext]'
    // js文件输出路径
    filename: 'js/app.js'
    

      

    设置的publicPath为 "assets/", 那么最终的访问路径就是 publicPath/loader设置的路径,例如图片路径就会是 assets/img/[name]_[hash:4].[ext]

    总结来说就是最终的url访问路径是拿publicPath+loader路径相拼接的

    接下来,我们npm start启动我们的项目,发现最终访问的是项目的根目录,而并没有去访问打包出来的那个index.html文件,在找出没有访问到index.html文件的原因之前,我们先来讲清楚webpack中几个非常容易混淆的路径问题

    1.output.path
    
    2.output.publicPath
    
    3.devServer.publicPath
    
    4.devServer.contentBase
    

      

    output.path 是静态资源的输出目录,打包后的资源都放到这里

    output.publicPath是静态资源的基础目录,设置这个目录后,最终的静态资源访问路径前面都会拼接上这个选项设置的值,这也方便我们单独设置静态资源服务器地址,例如:静态资源服务器地址是http://static.nodeing.com, 设置了这个值,最终访问图片的地址就会是 http://static.nodeing.com/assets/img/nodeing.com 这种形式,因此,这也是output.publicPath这个选项和后面devServer.publicPath比较大的区别,前者是可以设置http网址的

    devServer.publicPath这个选项是webpack-dev-server服务器的访问路径,我们知道当webpack-dev-server启动后,会把资源打包到内存,你不需要关注它在内存中的什么地方,你可以理解为打包后的资源也被输出了,只是输出到内存中,你无法在硬盘上看见而已,但是它提供了一个地址来供我们访问,devServer.publicPath就是用来设置访问内存中被打包出来的资源地址的,举例说明:

    output: {
            path: path.resolve(__dirname, 'dist/assets'),
            filename: 'js/app.js',
        },
    devServer: {
            open: true, 
            publicPath: '/aa'
        },
        其他配置省略...
    

      

    像上面这种配置,当服务器启动的时候,如果想访问到内存中的app.js,那么需要通过http://localhost:8080/aa/js/app.js

    回到开始的问题,npm start启动服务器后,无法访问到打包出来的index.html? 我们来找找具体的原因,说明一下几种路径的问题

    当前的完整的webpack配置是这样的:

    const path = require("path")
    
    
    const HtmlWebpackPlugin = require("html-webpack-plugin")
    
    const CleanWebpackPlugin = require("clean-webpack-plugin")
    
    module.exports = {
        entry: "./src/assets/js/index.js",
        output: {
            path: path.resolve(__dirname, 'dist/assets'),
            filename: 'js/app.js',
            publicPath: 'assets/'
        },
        plugins: [
            new HtmlWebpackPlugin({
                template: './src/index.html',
                filename: '../index.html'
            }),
            new CleanWebpackPlugin(['dist'])
        ],
        devServer: {
            open: true, 
            containtBase: 'src/'
            publicPath: '/aa'
        },
        module: {
            rules: [
                {
                    test: /.js$/,
                    use:['babel-loader'],
                    exclude: path.resolve(__dirname, 'node_modules')
                },
                {
                    test: /.css$/,
                    use: [
                        'style-loader',
                        {
                            loader: 'css-loader',
                            options: {
                                name: 'css/[name]_[hash:4].[ext]'
                            }
                        }
                    ]
                },
                // 处理文字
                {
                    test: /.(eot|svg|ttf|woff|woff2)$/,
                    use: [{
                        loader: "file-loader",
                        options: {
                            name: 'fonts/[name]_[hash:4].[ext]'
                        }
                    }]
                },
                {
                    test: /.(jpg|png|gif|webp|bmp)$/,
                    use: [{
                        loader: 'url-loader',
                        options: {
                            limit: 10240,
                            name: 'img/[name].[ext]'
                        }
                    }]
                }
            ]
        }
    
    }
    

      

    我们来解读几条关键的配置:

    1.path: path.resolve(__dirname, 'dist/assets'), 这条配置是打包后资源输出的目录,同样的当webpack-dev-server启动后,资源会打包到内存,用不太严谨但通俗的话来说你可以认为所有文件被打包到这个目录,只是这个目录放在内存而不是输出到硬盘,你访问这个目录里面的文件的时候,路径和打包到硬盘是看到的路径一样,例如:在硬盘上 dist/assets/js/app.js, 在内存中也通过这种目录结构访问就是了

    2.publicPath: 'assets/',这个配置,前面我们也讲到了,是静态资源的基础路径,可以返回去再阅读一下

    3.publicPath: '/aa', 这个配置是服务器访问内存的虚拟路径, http://localhost:8080/aa 这个地址,你可以认为是映射到了output.path设置的目录,不太严谨但通俗的说,你可以认为http://localhost:8080/aa 这个地址指向了这个目录(dist/assets/),那么你在http://localhost:8080/aa后面加 /js/app.js 就相当于访问 dist/assets/js/app.js,所以启动以后通过http://localhost:8080/aa/js/app.js是可以访问到这个js文件的

    4.filename: '../index.html',这个在HtmlWepackPlugin中的配置,设置了被打包出来的html位置,../表示往上一层返回,那就意味着,最终打包出来的结构是这样的:

    ├── dist
    |   ├── assets
    |       ├── css
    |       ├── img
    |       ├── js
    |   ├── index.html
    |
    

      

    我们通过http://localhost:8080/aa 能访问到dist/assets目录,也可以访问该目录下层级更深的文件,只需要在http://localhost:8080/aa 后面加文件路径就可以了,但是却永远无法返回到上层目录去访问到 index.html

    当访问不到内存中的index.html文件,webpack-dev-server就会去访问本地的路径,这个本地的路径就是containtBase: 'src/'这个选项设置的,所以npm start的时候,直接打开的是项目下的src目录

    好了,问题原因已经找出来了,接下来我们需要修改以下webpack配置,具体的思路就是

    1. 输出目录往上挪动一层    output.path 设置成 path.resolve(__dirname, 'dist'),
    2. 在每个loader上加深一层  js加深一层是这样的 assets/js/app.js  图片加深一层是这样的  assets/img/...,其他,同理
    3. ../index.html 改为当前目录  ./index.html
    4. output.publicPath的值设置来和devServer.publickPath的值一样,不然静态资源的访问地址会出错,返回404
    

    这样做,原来打包输出的目录变成了dist目录,而不是原来的dist/assets目录, 那么http://localhost:8080/aa 这个地址指向的内存虚拟目录就是 dist目录,那么通过http://localhost:8080/aa/index.html 就可以访问到内容了

    具体完整配置如下:

    const path = require("path")
    
    
    const HtmlWebpackPlugin = require("html-webpack-plugin")
    
    const CleanWebpackPlugin = require("clean-webpack-plugin")
    
    module.exports = {
        entry: "./src/assets/js/index.js",
        output: {
            path: path.resolve(__dirname, 'dist'),
            filename: 'assets/js/app.js',
            publicPath: '/aa/'
        },
        plugins: [
            new HtmlWebpackPlugin({
                template: './src/index.html',
                filename: './index.html'
            }),
            new CleanWebpackPlugin(['dist'])
        ],
        devServer: {
            open: true, 
            publicPath: '/aa'
        },
        module: {
            rules: [
                {
                    test: /.js$/,
                    use:['babel-loader'],
                    exclude: path.resolve(__dirname, 'node_modules')
                },
                {
                    test: /.css$/,
                    use: [
                        'style-loader',
                        {
                            loader: 'css-loader',
                            options: {
                                name: 'assets/css/[name]_[hash:4].[ext]'
                            }
                        }
                    ]
                },
                // 处理文字
                {
                    test: /.(eot|svg|ttf|woff|woff2)$/,
                    use: [{
                        loader: "file-loader",
                        options: {
                            name: 'assets/fonts/[name]_[hash:4].[ext]'
                        }
                    }]
                },
                {
                    test: /.(jpg|png|gif|webp|bmp)$/,
                    use: [{
                        loader: 'url-loader',
                        options: {
                            limit: 10240,
                            name: 'assets/img/[name].[ext]'
                        }
                    }]
                }
            ]
        }
    
    }
    

      

    通常output.publicPath和devServer.publicPath设置成 "/",这样我们就可以通过 http://localhost:8080/ 来访问打包出来的index文件了,自己动手改改,试试效果吧!!

  • 相关阅读:
    1451. Rearrange Words in a Sentence
    1450. Number of Students Doing Homework at a Given Time
    1452. People Whose List of Favorite Companies Is Not a Subset of Another List
    1447. Simplified Fractions
    1446. Consecutive Characters
    1448. Count Good Nodes in Binary Tree
    709. To Lower Case
    211. Add and Search Word
    918. Maximum Sum Circular Subarray
    lua 时间戳和时间互转
  • 原文地址:https://www.cnblogs.com/dadifeihong/p/8806969.html
Copyright © 2011-2022 走看看