美文网首页
Webpack4构建项目(初级)

Webpack4构建项目(初级)

作者: 罂粟1995 | 来源:发表于2020-08-08 09:46 被阅读0次

    本文学习用webpack4来构建一个vue项目。

    1. 初始化项目

    新建文件夹,控制台进入文件目录,执行:npm init ,一路回车,会生成一个package.json文件。

    2. 全局安装webpack

    全局安装:

    npm install webpack webpack-cli vue -g 
    //如果是mac,需要以管理员身份运行: sudo npm install webpack webpack-cli vue -g
    

    全局安装完成后,执行本地安装命令:

    npm install webpack webpack-cli vue vue-loader webpack-dev-server
    

    3. 安装依赖

    安装常用依赖包:vue-template-compiler css-loader file-loader style-loader sass-loader url-loader html-webpack-plugin cross-env

    npm install vue-template-compiler css-loader file-loader style-loader sass-loader url-loader html-webpack-plugin cross-env
    
    • vue-template-compiler
      将vue2.0模板预编译为渲染函数(template => ast => render),以避免运行时编译开销和csp限制,与vue-loader一起使用。

    • css-loader、style-loader
      webpack打包只处理js之间的依赖关系,如果js中引入了css文件,就需要css-loader来识别这个模块。css文件经过css-loader处理后,会导出一个包含style样式的js数组,style-loader的作用是将这些样式内容挂载到html页面上,使其生效。

    • html-webpack-plugin
      最常用的插件,可为html文件中引入的外部资源如script、link动态添加每次更新后的hash;可生成html入口文件,比如单页面上可以生成一个html文件入口,配置N个html-webpack-plugin则可以生成N个页面入口。

    • cross-env
      跨平台设置和使用环境变量。

    4. 编写webpack配置文件

    在目录下创建一个webpack.config.js文件,编写配置:

    const path = require('path');//nodejs中的基本包,处理文件路径
    const VueLoaderPlugin = require('vue-loader/lib/plugin');//vue-loader需要配合此插件使用
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    
    const config = {
        target: 'web',
        entry:path.join(__dirname, 'src/index.js'),
        output: {
            filename: 'bundle.js',
            path: path.join(__dirname,'dist')
        },
        module: {
            rules: [
                {
                    test: /\.vue$/,
                    use: 'vue-loader'
                },
                {
                    test: /\.(gif|jpg|jpeg|png|svg)/,
                    use: [
                        {
                            loader: 'url-loader',
                            options: {
                                limit: 1024,
                                name: '[name].[ext]'
                            }
                        }
                    ]
                }
            ]
        },
        plugins: [
            new VueLoaderPlugin(),
            new HtmlWebpackPlugin()
        ]
    }
    
    module.exports = config
    

    5. 区分开发环境和生产环境

    package.json中增加两行配置:
    "build": "cross-env NODE_ENV=production webpack --config webpack.config.js",//生产环境
    "dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js",//开发环境

    {
      "name": "vuetest",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "cross-env NODE_ENV=production webpack --config webpack.config.js",
        "dev": "cross-env NODE_ENV=development webpack-dev-server --config webpack.config.js"
      },
      "author": "",
      "license": "ISC",
      "dependencies": {
        "cross-env": "^7.0.2",
        "css-loader": "^4.2.0",
        "extract-text-webpack-plugin": "^3.0.2",
        "file-loader": "^6.0.0",
        "html-webpack-plugin": "^4.3.0",
        "mini-css-extract-plugin": "^0.9.0",
        "postcss-loader": "^3.0.0",
        "sass-loader": "^9.0.2",
        "style-loader": "^1.2.1",
        "url-loader": "^4.1.0",
        "vue": "^2.6.11",
        "vue-loader": "^15.9.3",
        "vue-template-compiler": "^2.6.11",
        "webpack": "^4.44.1",
        "webpack-cli": "^3.3.12"
      }
    }
    

    webpack.config.js:

    const path = require('path');//nodejs中的基本包,处理文件路径
    const VueLoaderPlugin = require('vue-loader/lib/plugin');//vue-loader需要配合此插件使用
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const webpack = require('webpack');
    
    const isDev = process.env.NODE_ENV === 'development'
    
    const config = {
        target: 'web',
        entry:path.join(__dirname, 'src/index.js'),
        output: {
            filename: 'bundle.js',
            path: path.join(__dirname,'dist')
        },
        module: {
            rules: [
                {
                    test: /\.vue$/,
                    use: 'vue-loader'
                },
                {
                    test: /\.(gif|jpg|jpeg|png|svg)/,
                    use: [
                        {
                            loader: 'url-loader',
                            options: {
                                limit: 1024,
                                name: '[name].[ext]'
                            }
                        }
                    ]
                }
            ]
        },
        plugins: [
            new VueLoaderPlugin(),
            new HtmlWebpackPlugin(),
            //通过配置了DefinePlugin,那么这里面的标识就相当于全局变量,便可以在src目录下直接取到当前环境变量。
            new webpack.DefinePlugin({
                'process.env': {
                    NODE_ENV: isDev ? '"development"' : '"production"'
                }
            })
        ]
    }
    
    //开发环境
    if(isDev){
        config.devtool = '#cheap-module-eval-source-map' // 调试代码时可以看到自己原本的代码,而不是编译后的
        config.devServer = {
            port: 8000,
            host: '0.0.0.0',
            overlay: {
                errors: true // 将webpack编译的错误显示在网页上面
            },
            open: true // 在启用webpack-dev-server时,自动打开浏览器
        }
        config.plugins.push(
            new webpack.HotModuleReplacementPlugin(),//模块热替换
            new webpack.NoEmitOnErrorsPlugin()
        )
    }
    
    module.exports = config
    

    6. 编写源文件

    新建src目录,在src目录下新建app.vue和index.js。
    app.vue:

    <template>
       <div>{{text}}</div>
    </template>
    
    <script>
    export default {
        data() {
           return {
              text: 'abc'
           }
        }
    }
    </script>
    
    <style>
    
    </style>
    

    index.js:

    import Vue from 'vue'
    import App from './app.vue'
    
    const root = document.createElement('div');
    document.body.appendChild(root);
    
    new Vue({
        render: (h) => h(App)
    }).$mount(root)
    

    尝试执行npm run buildnpm run dev查看效果,webpack会自动生成dist目录,将业务代码和类库代码打包成dist目录下的bundle.js文件。

    7. 区分开发环境和生产环境的打包配置,在生产环境下,用mini-css-extract-plugin来分离css

    通常,webpack将css内容都打包在bundle.js里,插件mini-css-extract-plugin能够将css和js模块分开打包,把css代码从js文件中抽离出来,单独出一个模块。
    执行npm install mini-css-extract-plugin
    修改webpack.config.js:

    const path = require('path');//nodejs中的基本包,处理文件路径
    const VueLoaderPlugin = require('vue-loader/lib/plugin');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const webpack = require('webpack');
    const miniCssExtractPlugin = require('mini-css-extract-plugin');
    
    const isDev = process.env.NODE_ENV === 'development'
    
    const config = {
        target: 'web',
        entry:path.join(__dirname, 'src/index.js'),
        output: {
            filename: 'bundle.js',
            path: path.join(__dirname,'dist')
        },
        module: {
            rules: [
                {
                    test: /\.vue$/,
                    use: 'vue-loader'
                },
                {
                    test: /\.(gif|jpg|jpeg|png|svg)/,
                    use: [
                        {
                            loader: 'url-loader',
                            options: {
                                limit: 1024,
                                name: '[name].[ext]'
                            }
                        }
                    ]
                }
            ]
        },
        // process.env.NODE_ENV = develpment
        plugins: [
            new VueLoaderPlugin(),
            new HtmlWebpackPlugin(),
            new webpack.DefinePlugin({
                'process.env': {
                    NODE_ENV: isDev ? '"development"' : '"production"'
                }
            })
        ]
    }
    
    //判断正式环境和开发环境
    if (isDev) {
        config.module.rules.push(
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.scss$/,
                use: [
                    'style-loader',
                    'css-loader',
                    'sass-loader'
                ]
            },
        )
        config.devtool = '#cheap-module-eval-source-map'
        config.devServer = {
            port: 8000,
            host: '0.0.0.0',
            overlay: {
                errors: true,
            },
            hot: true
        }
        config.plugins.push(
            new webpack.HotModuleReplacementPlugin(),
            new webpack.NoEmitOnErrorsPlugin()
        )
    } else {
        config.module.rules.push(
            {
                test: /\.css$/,
                use: [
                    miniCssExtractPlugin.loader,//注意:miniCssExtractPlugin与style-loader冲突,使用miniCssExtractPlugin时不要使用style-loader,否则会报错
                   // 'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.scss$/,
                use: [
                    miniCssExtractPlugin.loader,//注意:miniCssExtractPlugin与style-loader冲突,使用miniCssExtractPlugin时不要使用style-loader,否则会报错
                   // 'style-loader',
                    'css-loader',
                    'sass-loader'
                ]
            }
        )
        config.plugins.push(
            new miniCssExtractPlugin({
                filename: 'css/[name].[contenthash].css',
                allChunks: true
            }),
        )
    }
    
    module.exports = config
    

    8. 区分打包类库代码

    bundle.js包含了类库代码和业务代码,每次更新业务代码,都生成新的bundle.js,意味着浏览器中缓存的bundle.js也得更新。
    我们期望类库代码能够长时间地在浏览器中缓存,而不必随着业务代码的更新而更新。
    使用webpack.optimization.splitChunks分割类库代码,webpack4中可直接使用,无需安装任何插件,修改后的配置文件如下:

    const path = require('path');//nodejs中的基本包,处理文件路径
    const VueLoaderPlugin = require('vue-loader/lib/plugin');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const webpack = require('webpack');
    const miniCssExtractPlugin = require('mini-css-extract-plugin');
    
    const isDev = process.env.NODE_ENV === 'development'
    
    const config = {
        target: 'web',
        entry:path.join(__dirname, 'src/index.js'),
        output: {
            filename: 'bundle.js',
            path: path.join(__dirname,'dist')
        },
        module: {
            rules: [
                {
                    test: /\.vue$/,
                    use: 'vue-loader'
                },
                {
                    test: /\.(gif|jpg|jpeg|png|svg)/,
                    use: [
                        {
                            loader: 'url-loader',
                            options: {
                                limit: 1024,
                                name: '[name].[ext]'
                            }
                        }
                    ]
                }
            ]
        },
        // process.env.NODE_ENV = develpment
        plugins: [
            new VueLoaderPlugin(),
            new HtmlWebpackPlugin(),
            new webpack.DefinePlugin({
                'process.env': {
                    NODE_ENV: isDev ? '"development"' : '"production"'
                }
            })
        ]
    }
    
    //判断正式环境和开发环境
    if (isDev) {
        config.module.rules.push(
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.scss$/,
                use: [
                    'style-loader',
                    'css-loader',
                    'sass-loader'
                ]
            },
        )
        config.devtool = '#cheap-module-eval-source-map'
        config.devServer = {
            port: 8000,
            host: '0.0.0.0',
            overlay: {
                errors: true,
            },
            hot: true
        }
        config.plugins.push(
            new webpack.HotModuleReplacementPlugin(),
            new webpack.NoEmitOnErrorsPlugin()
        )
    } else {
        config.entry = {
            app:path.join(__dirname, 'src/index.js')
        }
        config.optimization = {
            splitChunks : {
                chunks: 'all',
                minSize: 30000,
                maxSize: 0,
                minChunks: 1,
                maxAsyncRequests: 5,
                maxInitialRequests: 3,
                automaticNameDelimiter: '~',
                name: true,
                cacheGroups: {
                    vendors: {
                        test: /[\\/]node_modules[\\/]/,
                        priority: -10
                    },
                    default: {
                        minChunks: 2,
                        priority: -20,
                        reuseExistingChunk: true
                    }
                }
            }
        },
        config.output.filename = '[name].[chunkhash:8].js'
        config.module.rules.push(
            {
                test: /\.css$/,
                use: [
                    miniCssExtractPlugin.loader,//注意:miniCssExtractPlugin与style-loader冲突,使用miniCssExtractPlugin时不要使用style-loader,否则会报错
                    //'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.scss$/,
                use: [
                    miniCssExtractPlugin.loader,//注意:miniCssExtractPlugin与style-loader冲突,使用miniCssExtractPlugin时不要使用style-loader,否则会报错
                   // 'style-loader',
                    'css-loader',
                    'sass-loader'
                ]
            }
        )
        config.plugins.push(
            new miniCssExtractPlugin({
                filename: 'css/[name].[contenthash].css',
                allChunks: true
            }),
        )
    }
    
    module.exports = config
    

    执行npm run build,dist目录下将生成业务代码app.js文件和类库代码vendors.js。

    多次打包,会发现dist目录下生成了多个hash值不同的vendor.js和app.js,这时我们需要安装插件,在每次打包前清除dist目录。

    npm install clean-webpack-plugin
    

    webpack.config.js :

    const path = require('path');//nodejs中的基本包,处理文件路径
    const VueLoaderPlugin = require('vue-loader/lib/plugin');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const webpack = require('webpack');
    const miniCssExtractPlugin = require('mini-css-extract-plugin');
    // 引入打包时清除 dist 目录的插件,引入时需要用对象{ CleanWebpackPlugin }包裹起来
    const {CleanWebpackPlugin} = require('clean-webpack-plugin');
    
    const isDev = process.env.NODE_ENV === 'development'
    
    const config = {
        target: 'web',
        entry:path.join(__dirname, 'src/index.js'),
        output: {
            filename: 'bundle.js',
            path: path.join(__dirname,'dist')
        },
        resolve: {
            alias: {
                '@': path.resolve(__dirname,'./src'),
            }
        },
        module: {
            rules: [
                {
                    test: /\.vue$/,
                    use: 'vue-loader'
                },
                {
                    test: /\.(gif|jpg|jpeg|png|svg)/,
                    use: [
                        {
                            loader: 'url-loader',
                            options: {
                                limit: 1024,
                                name: '[name].[ext]'
                            }
                        }
                    ]
                }
            ]
        },
        // process.env.NODE_ENV = develpment
        plugins: [
            new VueLoaderPlugin(),
            new HtmlWebpackPlugin(),
            new webpack.DefinePlugin({
                'process.env': {
                    NODE_ENV: isDev ? '"development"' : '"production"'
                }
            })
        ]
    }
    
    //判断正式环境和开发环境
    if (isDev) {
        config.module.rules.push(
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.scss$/,
                use: [
                    'style-loader',
                    'css-loader',
                    'sass-loader'
                ]
            },
        )
        config.devtool = '#cheap-module-eval-source-map'
        config.devServer = {
            port: 8000,
            host: '0.0.0.0',
            overlay: {
                errors: true,
            },
            hot: true
        }
        config.plugins.push(
            new webpack.HotModuleReplacementPlugin(),
            new webpack.NoEmitOnErrorsPlugin()
        )
    } else {
        config.entry = {
            app:path.join(__dirname, 'src/index.js')
        }
        config.optimization = {
            splitChunks : {
                chunks: 'all',
                minSize: 30000,
                maxSize: 0,
                minChunks: 1,
                maxAsyncRequests: 5,
                maxInitialRequests: 3,
                automaticNameDelimiter: '~',
                name: true,
                cacheGroups: {
                    vendors: {
                        test: /[\\/]node_modules[\\/]/,
                        priority: -10
                    },
                    default: {
                        minChunks: 2,
                        priority: -20,
                        reuseExistingChunk: true
                    }
                }
            }
        },
        config.output.filename = '[name].[chunkhash:8].js'
        config.module.rules.push(
            {
                test: /\.css$/,
                use: [
                    miniCssExtractPlugin.loader,
                    //'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.scss$/,
                use: [
                    miniCssExtractPlugin.loader,
                    //'style-loader',
                    'css-loader',
                    'sass-loader'
                ]
            }
        )
        config.plugins.push(
            new miniCssExtractPlugin({
                filename: 'css/[name].[contenthash].css',
                allChunks: true
            }),
            // 打包时,把 dist 目录下的文件内容先清除
            new CleanWebpackPlugin()
        )
    }
    
    module.exports = config
    
    

    9. 用babel将es6转译为浏览器能够识别的代码

    安装相应的包:

    npm install -D babel-loader @babel/core @babel/preset-env webpack
    

    创建一个与webpack.config.js同级的文件.babelrc,写入内容:

    {
        "presets" : [
           "@babel/preset-env"
        ]
    }
    

    webpack.config.js:

    const path = require('path');//nodejs中的基本包,处理文件路径
    const VueLoaderPlugin = require('vue-loader/lib/plugin');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const webpack = require('webpack');
    const miniCssExtractPlugin = require('mini-css-extract-plugin');
    // 引入打包时清除 dist 目录的插件,引入时需要用对象{ CleanWebpackPlugin }包裹起来
    const {CleanWebpackPlugin} = require('clean-webpack-plugin');
    
    const isDev = process.env.NODE_ENV === 'development'
    
    const config = {
        target: 'web',
        entry:path.join(__dirname, 'src/index.js'),
        output: {
            filename: 'bundle.js',
            path: path.join(__dirname,'dist')
        },
        resolve: {
            alias: {
                '@': path.resolve(__dirname,'./src'),
            }
        },
        module: {
            rules: [
                {
                    test: /\.vue$/,
                    use: 'vue-loader'
                },
                {
                    test: /\.(gif|jpg|jpeg|png|svg)/,
                    use: [
                        {
                            loader: 'url-loader',
                            options: {
                                limit: 1024,
                                name: '[name].[ext]'
                            }
                        }
                    ]
                },
                {
                    test: /\.js$/,
                    exclude: /node_modules/,
                    loader: "babel-loader"
                }
            ]
        },
        // process.env.NODE_ENV = develpment
        plugins: [
            new VueLoaderPlugin(),
            new HtmlWebpackPlugin(),
            new webpack.DefinePlugin({
                'process.env': {
                    NODE_ENV: isDev ? '"development"' : '"production"'
                }
            })
        ]
    }
    
    //判断正式环境和开发环境
    if (isDev) {
        config.module.rules.push(
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.scss$/,
                use: [
                    'style-loader',
                    'css-loader',
                    'sass-loader'
                ]
            },
        )
        config.devtool = '#cheap-module-eval-source-map'
        config.devServer = {
            port: 8000,
            host: '0.0.0.0',
            overlay: {
                errors: true,
            },
            hot: true
        }
        config.plugins.push(
            new webpack.HotModuleReplacementPlugin(),
            new webpack.NoEmitOnErrorsPlugin()
        )
    } else {
        config.entry = {
            app:path.join(__dirname, 'src/index.js')
        }
        config.optimization = {
            splitChunks : {
                chunks: 'all',
                minSize: 30000,
                maxSize: 0,
                minChunks: 1,
                maxAsyncRequests: 5,
                maxInitialRequests: 3,
                automaticNameDelimiter: '~',
                name: true,
                cacheGroups: {
                    vendors: {
                        test: /[\\/]node_modules[\\/]/,
                        priority: -10
                    },
                    default: {
                        minChunks: 2,
                        priority: -20,
                        reuseExistingChunk: true
                    }
                }
            }
        },
        config.output.filename = '[name].[chunkhash:8].js'
        config.module.rules.push(
            {
                test: /\.css$/,
                use: [
                    miniCssExtractPlugin.loader,
                    //'style-loader',
                    'css-loader'
                ]
            },
            {
                test: /\.scss$/,
                use: [
                    miniCssExtractPlugin.loader,
                    //'style-loader',
                    'css-loader',
                    'sass-loader'
                ]
            }
        )
        config.plugins.push(
            new miniCssExtractPlugin({
                filename: 'css/[name].[contenthash].css',
                allChunks: true
            }),
            // 打包时,把 dist 目录下的文件内容先清除
            new CleanWebpackPlugin()
        )
    }
    
    module.exports = config
    

    相关文章

      网友评论

          本文标题:Webpack4构建项目(初级)

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