首先全局安装:node、npm、webpack、webpack-cli

npm install webpack webpack-cli -D

接着创建打包配置文件:webpack.config.js

打包图片

npm init -y //生成配置文件package.json

此时webpack-test目录如下:
image.png

npm install url-loader -S  
//安装file-loader
//安装url-loader到当前并记录到package.json
 npm install file-loader -S 
 //安装file-loader :
 //生成的文件的文件名就是文件内容的
 //MD5哈希值并会保留所引用资源的原始扩展名

在开发模式的情况下:mode:'development'时:无论你的图片是否 使用,在(limit设置数值要在被打包的图片的大小范围以内的)都会生成dataUrl打包到bundele.js,而limit设置的数值小于图片本身大小,也会直接打包到dist文件当中,但只会生成图片本身而不是dataUrl
在生产模式的情况下:mode:'production'时:在(limit设置数值要在被打包的图片的大小范围以内的),图片使用:会生成dataUrl打包到bundle.js里面。不使用不会打包成dataUrl,也不会生成图片本身打包到dist文件中(直接去除无用代码)。如果设置的limit小于被打包图片的大小,无论使用使用了图片都会生成图片本身在dist文件当中。总结:优先级看来都是limit比较高

转换JS语句(非es5转换)

npm install babel-loader@8.0.0-beta.0 @babel/core @babel/preset-env webpack
// 把es6那些转换成es5
npm install @babel/plugin-transform-runtime -D 
npm install @babel/runtime -D
// 对es6降级es5的一个垫片,可以按需引入,模块化加载,不污染全局

此时目录如下:
image.png

  • babel-loader @babel/core 可以支持es6语法
  • @babel/preset-env 是根据浏览器或者运行环境来将es6转化成es5,比如根据browserslist
  • 补充说明1:@babel/polyfill 是对es6降级es5的一个垫片,是对babel-loader的补充,但是会污染全局,不能按需引入,不建议这种方式
  • 补充说明2:@babel/runtime @babel/plugin-transform-runtime也是对es6降级es5的一个垫片,可以按需引入,模块化加载,不污染全局,推荐使用
  • file-loader 或者 url-loader可以支持引入文件
  • file-loader不支持小文件转化为base64格式,但是可以为文件名添加hash值,url-loader可以支持小文件转化为base64格式,这两个可以搭配使用

详情可点击于此:https://babeljs.io/docs/en/next/babel-plugin-transform-runtime.html

打包CSS样式

处理sass
npm install sass-loader node-sass -D 
// 安装sass-loader、node-sass
npm install style-loader css-loader -D 
//安装 style-loader、css-loader

在webpack.config.js得module得rules:中添加
image.png
css-loader详情:https://www.webpackjs.com/loaders/css-loader/
sass-loader详情:https://www.webpackjs.com/loaders/sass-loader/
然后新建文件夹css里面创建test.scss文件测试一下:
此时目录如下:
image.png
然后此时输入webpack进行打包,但出现了一次错误,无论如何检查,感觉都好像没啥问题。
image.png
表示我文件错误出现在scss上,但是反复研究发现还是没问题呀?
最后发现是安装sass-loader版本有问题,这里需要打开你得在package.json文件,修改sass-loader得版本,修改为7.0.0就可以了
image.png
紧接着重新输入 npm i重新安装依赖,ok打包成功!
image.png

处理less
 npm install less-loader less -D
 //安装less 

然后webpack.config.js添加规则:
image.png
less-loader详情:https://www.webpackjs.com/loaders/less-loader/
然后在css文件夹中创建测试文件test2.less
image.png
然后进行打包测试,完成!!!!

我想着要是把打包的css和js分开怎么办?

这时候我们需要加入一个插件:MiniCssExtractPlugin

npm install mini-css-extract-plugin -D
//安装MiniCssExtractPlugin

提示:另外一个插件ExtractTextWebpackPlugin也可以进行分离,但在Webpack官方显示webpack4的ExtractTextWebpackPlugin不能用于css,需要改用MiniCssExtractPlugin
安装完后webpack.config.js文件头部直接引入:

const MiniCssExtractPlugin = require('mini-css-extract-plugin');

其次还需要添加到rules和plugins,并进行修改:
image.png

要处理css兼容各个浏览器,自动在css添加前缀,需要下载以下插件

npm install postcss-loader autoprefixer postcss -D
//在之前项目webpack1.x版本升级到webpack4.x版本,使用postcss-loader代替autoprefixer。这边同时做一下兼容。

安装完后需要先在webpack.config.js同目录下新建文件postcss.config.js,注意这个文件不创建是编译不成功的,编辑内容为:

module.exports = {
    plugins: [
        require('autoprefixer')({
            /* ...options */ })
    ]
}
//postcss.config.js

接着在webpack.config.js文件中添加:
image.png
需要注意的是:使用postcss-loader时,需要在css-loader之后style-loader,但要其他预处理程序加载程序(例如sass|less|stylus-loader,如果使用)之前**使用它。

打包字体

新建font文件夹存放字体包,并在css中引入,其次还需要在webpack.config.js中加入loader内容(代码如下:)

{
    test: /\.(woff|woff2|eot|ttf|otf)$/,
    use: [
        'file-loader'
    ]
}

image.png

NPM 脚本

考虑到用 CLI 这种方式来运行本地的 webpack 不是特别方便,我们可以设置一个快捷方式。在 package.json 添加一个 npm 脚本(npm script):
image.png
(这一段是官方的原话,这边引用一下,就当是我个人学习笔记吧)
然后运行以下命令看看是否正常:

npm run build  //打包

自动引入打包生成得js得插件:html-webpack-plugin

 npm install html-webpack-plugin -D
 //安装HtmlWebpackPlugin

紧接着进行配置,代码如下:

const HtmlWebpackPlugin = require('html-webpack-plugin'); //自动引入打包生成得js

 plugins: [ //plugins 插件用于执行范围包括,从打包优化和压缩,一直到重新定义环境中的变量
        new HtmlWebpackPlugin({
            minify: {
                collapseWhitespace: true, //清除空格
                removeAttributeQuotes: true, //清除多余引号
                removeComments: true //删除注释

            },
            title: 'Output Management', //替代原title,需要在src文件夹下的index.html中配置
            template: path.resolve(__dirname, './src/index.html'), //要打包的html文件路径
            filename: 'index.html' //打包后输出的html文件名
        })
    ],

然后在src文件夹下新建文件index.html,因为上面使用了自定了title,所以需要在index.html中设置title:

<title><%= htmlWebpackPlugin.options.title %></title>

//把 Document 设置为 <%= htmlWebpackPlugin.options.title %>

image.png

输入npm run build,此时将生成了打包后dist文件夹,里面的index.html的title已经被替换,并自动引入了js和css文件:
image.png
html-webpack-plugin详情:https://webpack.js.org/guides/output-management/#conclusion

清理/dist文件夹:

npm install clean-webpack-plugin -D
//安装clean-webpack-plugin

安装后引入配置:

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

plugins: [  //plugins 插件用于执行范围包括,从打包优化和压缩,一直到重新定义环境中的变量
        new CleanWebpackPlugin() 
]

clean-webpack-plugin详情:https://webpack.js.org/guides/output-management/#conclusion

压缩单独的css文件

npm install  optimize-css-assets-webpack-plugin -D
//安装optimize-css-assets-webpack-plugin

配置文件:

const OptimizeCssAssetsWebpackPlugin = require('optimize-css-assets-webpack-plugin'); //压缩单独的css文件

plugins: [ //plugins 插件用于执行范围包括,从打包优化和压缩,一直到重新定义环境中的变量
        new OptimizeCssAssetsWebpackPlugin(),
]

optimize-css-assets-webpack-plugin详情:https://www.npmjs.com/package/optimize-css-assets-webpack-plugin

去除无用的css样式

npm install purifycss-webpack purify-css -D
//安装purifycss-webpack purify-css
const PurifyCSSPlugin = require('purifycss-webpack'); //css优化去重复无效代码
const glob = require('glob'); //css优化
plugins: [ //plugins 插件用于执行范围包括,从打包优化和压缩,一直到重新定义环境中的变量
        new PurifyCSSPlugin({
            paths: glob.sync(path.join(__dirname, './src/*.html')),
        })
]

purifycss-webpack-plugin详情:https://www.npmjs.com/package/purifycss-webpack

使用DefinePlugin设定创建全局变量

因此利用全局变量这一点来设置全局变量来区分开发环境和正式环境。
webpack.config.js 文件代码如下:

const webpack = require('webpack');

new webpack.DefinePlugin({
'SERVICE_URL': JSON.stringify('https://dev.example.com'),
  PROCESS.VERSION:  JSON.stringify('2.0.1'),
  PROCESS.ENVIRONMENT:  '"dev"'
  'process.env': {
        NODE_ENV: JSON.stringify(process.env.NODE_ENV)
    }               
});

注意:该plugin直接做文本替换,指定的值必须包括引号。
一般来讲,需要使用单引号"production"或使用JSON.stringify('production')
DefinePlugin中的每个键,是一个标识符或者通过.作为多个标识符。

  • 如果value是一个字符串,它将会被当做code片段
  • 如果value不是字符串,它将会被stringify(包括函数)
  • 如果value是一个对象,则所有key的定义方式相同。
  • 如果key有typeof前缀,它只是对typeof 调用定义的。

process.env.NODE_ENV :大概说说这个变量的问题,在node中,有全局变量process表示的是当前的node进程。process.env 属性返回的是一个包含用户环境信息的对象,process.env中并不存在NODE_ENV这个东西。NODE_ENV是用户一个自定义的变量,在webpack中它的用途是判断生产环境或开发环境的依据的。
我们可以直接在cmd环境配置即可,查看环境变量,添加环境变量,删除环境变量等操作。

#node中常用的到的环境变量是NODE\_ENV,首先查看是否存在 
set NODE\_ENV 

#如果不存在则添加环境变量 
set NODE\_ENV\=production 

#环境变量追加值 set 变量名\=%变量名%;变量内容 
set path\=%path%;C:\\web;C:\\Tools 

#某些时候需要删除环境变量 
set NODE\_ENV\=

因此利用这一点,我们可以在我们package.json文件中进行修改,
package.json 文件代码如下:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "NODE_ENV=production webpack",
    "dev": "NODE_ENV=development"
  },

当我们设置完以后 npm run build 打包,这个时候process.env.NODE_ENV 才会真正打印出 production,
可以尝试在src文件下的index.js进行打印测试

console.log(process.env.NODE_ENV)
//注意这里的打印的process.env.NODE_ENV 是我在webpack.config.js通过process.env.NODE_ENV利用new webpack.DefinePlugin()插件设置的属性值,

这时可能会出现一个打包异常:
image.png
这是我们可以利用这个脚本:

cross-env跨平台设置和使用环境变量的脚本

当我们使用 NODE_ENV = production 来设置环境变量的时候,大多数windows命令会提示将会阻塞或者异常,或者,windows不支持NODE_ENV=development的这样的设置方式,会报错。因此我们就可以使用 cross-env命令。
先安装:

npm install cross-env -D

然后在package.json中进行修改:

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "cross-env NODE_ENV=production webpack",
    "dev": "cross-env NODE_ENV=development"
  },

最后重新打包编译:
image.png
成功!!!

接下里也顺便设置全局变量来区分开发环境和正式环境:


根目录下创建config文件夹并新建api.js:

const NODE_ENV = process.env.NODE_ENV;

const config = {
     production: {
        FOO_API: 'production.foo.com',
        BAR_API: 'production.bar.com',
        BAZ_API: 'production.baz.com',
     },
     development: {
        FOO_API: 'development.foo.com',
        BAR_API: 'development.bar.com',
        BAZ_API: 'development.baz.com',
     },
     test: {
        FOO_API: 'test.foo.com',
        BAR_API: 'test.bar.com',
        BAZ_API: 'test.baz.com',
     }
}

module.exports = config[NODE_ENV];

并且package.json的scripts设置为

"scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build:qa": "cross-env NODE_ENV=test webpack",
    "build:dev": "cross-env NODE_ENV=development",
    "build:prod": "cross-env NODE_ENV=production webpack"
  },

webpack.config.js:

const apiConfig = require('./config/api'); //引入config/api.js 文件
new webpack.DefinePlugin({
    'SERVICE_URL': JSON.stringify('https://dev.example.com'),
    'process.env': {
        NODE_ENV: JSON.stringify(process.env.NODE_ENV)
    },
    API_CONFIG: JSON.stringify(apiConfig)
}),

这时候npm run build 在index.js输出打印一下

console.log(API_CONFIG.BAR_API);
//执行结果:production.bar.com

source-map 方便调试代码

devtool可选值:

  • source-map 【用于生产环境】
  • eval-source-map
  • eval-cheap-module-source-map
  • eval-cheap-source-map
  • eval 【建议开发环境用这个】

就可以把打包后的代码变成和开发的时候一样
直接在文件webpack.config.js进行引入

devtool :'source-map', //更容易地追踪错误和警告,方便在浏览器看见编译之前的代码,而非编译之后的
// 1、source-map:产生文件,产生行列
// 2、eval-source-map:不产生文件,产生行类
// 3、cheap-source-map:产生文件,不产生列
// 4、cheap-module-eval-source-map:不产生文件,不产生列

会打包生成.map文件方便调试。
image.png`

source-map详情:https://www.webpackjs.com/configuration/devtool/

快速搭建本地运行环境

webpack-dev-server:启动服务和支持热替换作用

为你提供了一个简单的 web 服务器,并且能够实时重新加载(live reloading)。

 npm install webpack-dev-server -D
 //安装 webpack-dev-server

webpack.config.json文件设置如下:

devServer: {
        contentBase: path.join(__dirname, "./dist"), // 开服务器的根路径,和output同目录
        historyApiFallback: true, //这个配置属性是用来应对返回404页面时定向到特定页面用的,任意的 404 响应都可能需要被替代为 index.html
        host: '0.0.0.0', //设置服务器的主机号,默认是localhost
        port: 7000, //输出端口号
        inline: true, //实时刷新 package.json文件scripts dev中添加--inline后可以不需要添加
        hot: true, //热替换功能 即不刷新页面,只对于修改的部分进行调整。默认是不设置就是会刷新页面
        compress: true, //这是一个布尔型的值,当它被设置为true的时候对所有的服务器资源采用gzip压缩
        overlay: true, //用于在浏览器输出编译错误的,默认是关闭的,需要手动打开
        stats: "errors-only", //这个配置属性用来控制编译的时候shell上的输出内容,因为我们并不需要所有的内容,而只是需要部分的如errors等
        open: true, // 自动打开浏览器
        proxy: {
             "/api": {
                 target: "http://localhost:3000",
                 pathRewrite: { "^/api": "" }
             }
         } //重定向是解决跨域的好办法,当后端的接口拥有独立的API,而前端想在同一个domain下访问接口的时候,可以通过设置proxy实现。
        //一个 “/api/users”地址的请求将被重定向到”http://10.10.10.10:3000/api/users“,如果不希望”api”在传递中被传递过去,可以使用rewrite的方式实现。
    },

package.json文件设置如下:

"scripts": {
    "dev": "cross-env NODE_ENV=development webpack-dev-server --inline"
  }

image.png
我这边只是做了简单的配置而已,然后执行命令 npm run dev
这时候由于设置了open 会自动打开浏览器访问http://localhost:7000/
读取你的页面。
webpack-dev-server详情:https://www.webpackjs.com/guides/development/#使用-webpack-dev-server

模块热替换(Hot Module Replacement 或 HMR)

模块热替换(Hot Module Replacement 或 HMR)是 webpack 提供的最有用的功能之一。它允许在运行时更新各种模块,而无需进行完全刷新。
模块热替换功能一般用于开发环境。
配置 devServer

devServer: { 
    contentBase: \[path.join(\_\_dirname, "dist")\], 
    compress: true, port: 9000, // 启动端口号 
    hot: true, // 启用 webpack 的模块热替换特性 
    inline: true, 
    publicPath: "/", // 和上文 output 的“publicPath”值保持一致 
}

配置 plugins

plugins: [ // 开启全局的模块热替换(HMR)  
    new webpack.HotModuleReplacementPlugin(), 
    // 当模块热替换(HMR)时在浏览器控制台输出对用户更友好的模块名字信息  
    new webpack.NamedModulesPlugin()
]

热替换详情:https://www.webpackjs.com/guides/hot-module-replacement/

准备好全部工作,最后搭建vue的项目:

搭建Vue项目

npm install vue-loader vue-template-compiler vue-style-loader -D
npm install vue -S

vue-loader 作用解析.vue文件
vue-style-loader 作用解析.vue的css
vue-template\-compiler 作用编译模板
vue 一个用于构建用户界面渐进式的MVVM框架

安装完毕后需要进行plugins的配置和loader的引入
loader配置:
注意:我的scss的loader中use的style-loader已经修改为vue-style-loader
我这里app.vue当中使用的是scss的写法,所以解析sass就好了

module: {
        rules: [
            // loader 让 webpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)
            // style-loader 将 JS 字符串生成为 style 节点
            // css-loader 将 CSS 转化成 CommonJS 模块
            // sass-loader 将 Sass 编译成 CSS
            // less-loader 将 Less 编译成 CSS
            {
                test: /\.css$/,
                use: [MiniCssExtractPlugin.loader, 'css-loader', 'postcss-loader'],
                exclude: /node_modules/ //去除不必要的构建
            },
            {
                test: /\.scss$/,
                use: ['vue-style-loader', 'css-loader', 'postcss-loader', 'sass-loader'],
                exclude: /node_modules/ //去除不必要的构建
            },
            {
                test: /\.less$/,
                use: ['vue-style-loader', 'css-loader', 'postcss-loader', 'less-loader'],
                exclude: /node_modules/ //去除不必要的构建
            },
            {
                test: /\.(png|jpeg|jpg|gif|svg)$/,
                use: [{
                    loader: 'url-loader',
                    options: {
                        limit: 11024,
                        fallback: {
                            loader: 'file-loader',
                            options: {
                                name: '[name].[hash:6].[ext]'
                            }
                        }
                    }
                }],
                exclude: /node_modules/
            },
            {
                test: /\.(woff|woff2|eot|ttf|otf)$/,
                use: [
                    'file-loader'
                ]
            },
            {
                test: /\.js$/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env'],
                        plugins: [
                            '@babel/plugin-transform-runtime'
                        ]
                    }
                },
                exclude: /node_modules/
            },
            {
                test: /\.vue$/,
                use: [
                    'vue-loader'
                ],
                exclude: /node_modules/
            }
        ]
    }

plugins配置:

const VueLoaderPlugin = require('vue-loader/lib/plugin');

plugins: [
    new VueLoaderPlugin()
]

最后进行测试,修改src目录底下的index.js文件:

import img11 from './images/img_2.png';
import './css/test.scss';
import './css/test1.css';
import './css/test2.less';
import print from './print.js';
print();

import Vue from 'vue';
import App from './components/app.vue';
new Vue({
    el: '#app',
    render: h=>h(App)
})

修改index.html文件:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
     <div id="app"></div>
     <script src="./dist/bundle.js"></script>
</body>
</html>

在src文件夹底下生成components文件夹新建app.vue

<template>
    <div class="app">
        <h1>3333</h1>
        <div>asdjklasjdlkas</div>
    </div>
</template>

<script>
    export default {
        
    }
</script>

<style lang="scss" scoped>
.app{
    h1{
        color: red;
    }
}
</style>

最后目录如下:
image.png

npm run dev 编译启动浏览器读取文件,热替换

大功告成!!!!!

总结一下:

项目运行

  • npm i安装依赖
  • npm run dll构建出不需打包的vendor包
  • npm run build构建打包

entry 入口文件

output 出口文件名及路径

webpack-dev-server可以开启本地服务器,或者设置proxy代理

source-map 可以生成.map文件,方便调试

mode取值development或者production,production模式下js会自动压缩

loader与plugin

  • html-webpack-plugin 可以将打包后的资源自动引入到html中
  • style-loader css-loader可以支持css模块
  • sass-loader node-sass 可以支持sass
  • less-loader 可以支持less
  • postcss-loader autoprefixer 可以支持自动加css前缀
  • mini-css-extract-plugin 或者 extract-text-webpack-plugin可以支持css从js中抽离
  • optimize-css-assets-webpack-plugin 可以压缩css
  • purify-css purifycss-webpack 可以去除无用的css
  • babel-loader @babel/core 可以支持es6语法
  • @babel/preset-env 是根据浏览器或者运行环境来将es6转化成es5,比如根据browserslist
  • 补充说明1:@babel/polyfill 是对es6降级es5的一个垫片,是对babel-loader的补充,但是会污染全局,不能按需引入,不建议这种方式
  • 补充说明2:@babel/runtime @babel/plugin-transform-runtime也是对es6降级es5的一个垫片,可以按需引入,模块化加载,不污染全局,推荐使用
  • file-loader 或者 url-loader可以支持引入文件
  • file-loader不支持小文件转化为base64格式,但是可以为文件名添加hash值,url-loader可以支持小文件转化为base64格式,这两个可以搭配使用
  • vue-loader vue-template-compiler 可以支持编译.vue文件
  • clean-webpack-plugin 可以清除打包后的文件夹
  • webpack.HotModuleReplacementPlugin webpack自带的热替换plugin与devServer的hot:true结合使用,使页面可以不刷新

源码:https://github.com/MaxFung3t/webpack-test


小添走天下
21 声望1 粉丝

一个无任何爱好的拼搏君。