webpack入门系列之三——生产配置、样式文件分离及输出清理

374 阅读10分钟

本文已在我的公众号上发布,更多原创技术文章,请关注我的公众号“字节逆旅”

今天带来webpack入门之三,这可能是入门系列最后一篇了,后面会进入进阶系列。之所以说是入门最后一篇,是因为我觉得很多项目只需要有这个入门级别就可以很好的实现升级维护了。有些老项目,现在躺在那里,偶尔改下东西,一堆的html+css+js,你根本搞不清楚有多少废代码,找东西难不说,部署起来也麻烦。

现在vue、react很流行,新项目基本用这些新框架,组件化开发确实是趋势,但是他们再怎么发展也离不开构建工具,顶多在webpack等工具上进行再封装。现在vuecli3出来后,我感觉学习成本反而变高了,直观感觉就是文档不清爽,知识零碎。其实回到本源,vuecli3就是基于webpack来的,而且webpack本身非常好学,可以由浅到深,逐步深入。你可以不用学vue、react,只要你会html+css+js就可以用上这个打包工具。很多人不懂webpack是因为一开始就没接触过,然后最先接触的反而是vue或者react框架,结果组件api已经学晕了,突然听说这个其实是webpack的东西,一下就更懵了,所以在不懂原理的情况下,别人的包装让你更加的迷茫。有些人只想会用就行,有些人是有点搞不懂的就想搞明白。那如果你是个前端,想搞清楚本质本源的东西,真的建议你学下webpack。就从这篇入门开始吧,一小时入门webpack

本文是基于前面两篇文章来的,每一篇都不长,照着敲代码会很容易上手。一小时入门webpackwebpack入门系列之二——插件使用及热更新打包,代码已经上传到github,每节课的代码都放在独立的文件夹里,而且都是基于前面一节累加变化,所以完整的代码就是最新的教程讲解里。最好是自己动手敲出来,如果有需要可以下载下来参考:https://github.com/bridgeToVillage/webpack-learning。开始本节前,先将第二节最终代码拷贝一份,放在新建的文件夹section three。

生产配置

前面第一篇提到过webpack.config.js文件中的mode这个配置参数用来指定当前的运行环境的,这个配置是webpack4提出来的,它有三个值:"production" | "development" | "none",production就是生产环境,即最终部署环境;development是开发环境;none即不指定环境因素,默认是production。开发和生产环境还是有很大区别的,按官网说法,在开发环境中,我们需要具有强大的、具有实时重新加载或热模块替换能力的 source map 和本地服务。而在生产环境中,我们的目标则转向于关注更小的输出文件,更轻量的 source map,以及更优化的资源,以改善加载时间。这里提到的souce map,意思就是资源地图,后面进阶部分会讲到,你可以上官网查下。

刚刚讲了两种环境的区别,主要是为了强调把两种环境的配置分开管理的重要性。那问题来了,用两个配置,那把webpack.config.js拷贝一份,将mode分别设置为两个环境不就可以了?这没问题,但是也可以将公用部分抽出来,在各个环境中引用公用部分,这样管理起来更方便。

这里就要提到一个工具:webpack-merge,可以专门用来合并webpack配置,可以通过npm安装;

安装
npm install --save-dev webpack-merge
抽离公用配置

在根目录新建一个webpack.common.js文件,把webpack.config.js文件内容拷贝一份进去,删掉devServer、watch部分,只留下公用部分。

生产及开发环境配置

然后将webpack.config.js重命名为webpack.dev.js,再将内容修改为以下内容:

'use strict'
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
    devtool'inline-source-map',
    watchtrue,
    devServer: {
     contentBase'./dist',
     hottrue
   }
 });

再新建一个webpack.prod.js文件,即生产环境配置,输入以下内容:

'use strict'
const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
 });
npm scripts

修改npm scripts,将原来的启动配置修改下,将dev配置修改为

"dev""webpack-dev-server --config webpack.dev.js --open"

因为之前都是默认从webpack.config.js中启动不用写文件名,现在开发和生产环境分开,就要将启动指向文件标名。dev代表开发环境,我们开发时就运行 npm run dev看浏览器运行效果。那么构建的时候,就要调用生产环境的配置了,在原来的构建节点build后面加上启动文件就行。

"build""webpack --config webpack.prod.js"

然后可以运行下npm run dev看下效果,没问题

再运行下npm run build打包,也是没问题的。

总结下,就是将公用部分抽出来独立,像loader及插件这种经常会添加修改的就单独放,后期只修改common.js,应用到开发、生产环境,就在对应的配置文件中merge这个工具合并就是一个完整配置了。这样即进行了环境区分,而且公共配置被抽离,实现了互不干扰也不会增加工作量。

css文件分离构建

目前我们打包后,js代码还有样式全输出到index.js文件中,前面我们在讲到图片构建时,将图片放在样式中,然后通过url-loader打包成base64数据,所以整个的输出文件中就看起来一堆的东西,分不清你我,很混乱。 这里就讲到一个插件ExtractTextWebpackPlugin,可以将样式与js分离。

安装ExtractTextWebpackPlugin
npm install --save-dev extract-text-webpack-plugin

接下来要注意了,因为我们已经将生产和开发环境的配置进行了分离,而且这个插件是要在生产环境,也就是构建的时候发挥作用,所以先将之前在公用配置文件webpack.common.js中的样式相关loader删掉并移植到webpack.dev.js文件中,最后在webpack.prod.js文件中应用此插件。直接上代码,三个配置文件具体代码如下:

webpack.common.js

'use strict'

const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    entry: {
        index'./src/index.js',
    },
    output: {
        path: path.join(__dirname,'dist'),
        filename'index.js'
    },
    plugins: [
        new HtmlWebpackPlugin({
           title'leaningwebpack',
           filename'webpack-index.html',
           favicon'webpack.ico'
        }),
        new webpack.HotModuleReplacementPlugin()
    ],
    module: {
        rules: [
            {
                test/.js$/,
                use'babel-loader',
                exclude/node_modules/
            },
            {
                test/.(jpg|png|gif|jpeg)$/,
                use: [{
                    loader:'url-loader',
                    options: {
                        limit:160000,
                        name'imgs/[name].[hash].[ext]'
                    }
                }]
            }
         ]
      }
}
webpack.dev.js

'use strict'

const merge = require('webpack-merge');
const common = require('./webpack.common.js');
module.exports = merge(common, {
    devtool'inline-source-map',
    watchtrue,
    devServer: {
     contentBase'./dist',
     hottrue
   },
   module: {
       rules: [
        {
            test/.css$/,
            use: [
                'style-loader',
                'css-loader'
            ]
        },
        {
            test/.less$/,
            use: [
                'style-loader',
                'css-loader',
                'less-loader'
            ]
        },
       ]
   }
 });

webpack.prod.js

'use strict'

const merge = require('webpack-merge');
const common = require('./webpack.common.js');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = merge(common, {
    plugins: [
        new ExtractTextPlugin({filename"style.css"})],
    module: {rules: [
        {
            test/.less$/,
            use: ExtractTextPlugin.extract({
                fallback'style-loader',
                use: ['css-loader''less-loader']
              })
        }]
    }
 });


然后运行npm run build,就会看到在dist目录下生成了样式文件:style.css,这个文件在html文件中被引用了。我们运行npm run dev时,它会走开发环境的配置,仍然可以正常解析样式文件。

清理输出文件

接下来讲最后webpack入门的最后一个知识点:清理输出文件。 我们可以看到在dist文件夹里,有一些历史文件index.html,这是我在webpack.common.js文件里修改了东西,输出文件变了,但是之前的文件仍然会存在,这样日积月累就会有很多垃圾。这个比较简单,安装一个插件,引用一下就行了,记住,这个也是生产环境中配置。

安装clean-webpack-plugin
npm install clean-webpack-plugin --save-dev
插件配置

const CleanWebpackPlugin = require('clean-webpack-plugin');


 plugins: [
        new CleanWebpackPlugin(['dist']),
        new ExtractTextPlugin({filename"style.css"})],


代码我就不写完整了,应该能明白怎么回事了吧。然后运行npm run build,看下效果。

结果报错了:CleanWebpackPlugin is not a constructor。

在网上找了下,插件引用需要这么写:

const {CleanWebpackPlugin} = require('clean-webpack-plugin');

{CleanWebpackPlugin}这是es6的新语法,将变量直接写入大括号就是一个对象了。为什么要这么写呢?可以看看这个插件的源码,在依赖包里找到这个文件

exports.CleanWebpackPlugin = void 0;
class CleanWebpackPlugin = { ... }
exports.CleanWebpackPlugin = CleanWebpackPlugin;

也就是说,这个插件导出的是一个变量exports.CleanWebpackPlugin,但是我们需要的是一个类CleanWebpackPlugin ,所以加上括号就可以了,我个人觉得这是插件的一个bug。

修改好后,再运行npm run build就可以看到效果了,dist目录下之前的文件删除了,生成了新文件。

好了,入门系列今天收官了,希望你能有收获。封城期间我开始真正打理公众号,原创确实不易,如果觉得对你有用,就点个在看吧,欢迎关注,后面会有高阶用法介绍。

代码地址:github.com/bridgeToVil…

本文发表在我的公众号 字节逆旅,如果对大前端技术感兴趣,欢迎扫码关注