webpack4 开发环境搭建

webpack4 开发环境搭建

npm 初始化项目

1
yarn init

安装webpack依赖

1
yarn add webpack webpack-dev-server webpack-cli @webpack-cli/init --dev

webpack 初始化

1
npx webpack-cli init

1
2
3
4
5
6
7
? Will your application have multiple bundles? Yes
? Type the names you want for your modules (entry files), separated by comma [example: app,vendor] app
? What is the location of "app"? [example: ./src/app] ./src/app
? Which folder will your generated bundles be in? [default: dist]: dist
? Will you be using ES2015? Yes
? Will you use one of the below CSS solutions? SASS
yarn add v1.12.1

添加编译插件

1
2
3
4
5
6
## 二选一
## 1. class 写法 向下兼容
yarn add @babel/plugin-proposal-class-properties --dev
## 2. babel 支持 import 
## yarn add @babel/plugin-syntax-dynamic-import --dev
yarn add @babel/preset-env @babel/core cross-env --dev

安装loader

1
yarn add html-withimg-loader url-loader file-loader style-loader postcss-loader --dev

插件安装

1
yarn add mini-css-extract-plugin uglifyjs-webpack-plugin clean-webpack-plugin copy-webpack-plugin extract-css html-webpack-plugin --dev

安装webpack-chain

1
yarn add webpack-chain --dev

此处webpack-chain5.0.1版本,是针对webpack 4维护的,需特别注意

github地址:webpack-chain

创建webpack.config.js

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
const path = require('path');
const isProd = process.env.NODE_ENV === 'production';
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

const WebpackChain = require('webpack-chain');

const config = new WebpackChain();

config.when(isProd,config=>{
    config.entry('index').add('./src/index.js');
}).when(!isProd,config=>{
    config.entry('index').add('./src/index.js');
})
// Modify output settings
    .output
    .path(path.join(__dirname, "dist")).filename('[name].js').end()
    .when(isProd, config => {
        config.mode('production');
    }).when(!isProd,config=>{
    config.mode('development').devtool('source-map');
}).end();

/**
 * module
 */
config
    .module
    .rule("compile")
    .test(/\.js$/)
    .include.add(path.join(__dirname,'src')).end()
    .exclude.add(/node_modules/).end()
    .use('babel').loader("babel-loader")
    .options({
        presets: ['@babel/preset-env'],
        plugins: ['@babel/plugin-proposal-class-properties']
    });

config.module
    .rule('images')
    .test(/\.(png|jpg|jpeg|gif)/)
    .use('url-loader')
    .loader('url-loader')
    .options({
        limit: 1 * 1024,
        name: path.posix.join("images","[name].[ext]")
    })

// do not base64-inline SVGs.
// https://github.com/facebookincubator/create-react-app/pull/1180
config.module
    .rule('svg')
    .test(/\.(svg)(\?.*)?$/)
    .use('url-loader')
    .loader('url-loader')
    .options({
        limit: 1024 * 3,//30kb
        fallback: 'file-loader'
    })

config.module
    .rule("fonts")
    .test(/\.(woff2?|eot|ttf|otf)(\?.*)?$/i)
    .use('url-loader')
    .loader('url-loader')
    .options({
        limit: 10000,
        fallback: {
            loader: 'file-loader',
            options: {
                name: path.posix.join("fonts","[name].[ext]")
            }
        }
    });

config.when(isProd,config=>{
    config.module.rule("css").test(/\.(sa|sc|c)ss$/)
        .use("style").loader(MiniCssExtractPlugin.loader);
}).when(!isProd,config=>{
    config.module.rule("css").test(/\.(sa|sc|c)ss$/)
        .use("style-loader").loader("style-loader");
});

config.module.rule("css").test(/\.(sa|sc|c)ss$/)
    .use('css').loader("css-loader").end()
    .use('postcss-loader').loader('postcss-loader');

config.module.rule("scss").test(/\.(sa|sc)ss$/).use("sass-loader").loader("sass-loader");

config.module.rule("lass").test(/\.less$/).use("less-loader").loader("less-loader");

//config.module.rule("html").test(/\.(htm|html)$/i).use("html").loader('html-withimg-loader');

/**
 * plugin
 */
config.when(isProd,config=>{
    const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
    const CleanWebpackPlugin = require('clean-webpack-plugin');
    const CopyWebpackPlugin = require("copy-webpack-plugin");

    config.plugin("clear").use(new CleanWebpackPlugin([path.join(__dirname, 'dist')]));
    config.optimization.splitChunks({
        cacheGroups: {
            commons: {
                chunks: "initial",
                name: "common",
                minChunks: 2,
                maxInitialRequests: 5, // The default limit is too small to showcase the effect
                minSize: 0, // This is example is too small to create commons chunks
                reuseExistingChunk: true // 可设置是否重用该chunk(查看源码没有发现默认值)
            }
        }
    });
    config.plugin("js").use(new UglifyJSPlugin({}));
    config.plugin('extract-css')
        .use(MiniCssExtractPlugin, [{
            filename: "css/[name].css",
            chunkFilename: "css/[name].css"
        }]);
    // config.plugin('copy').use(new CopyWebpackPlugin([
    //     {
    //         from:"./src/sass",
    //     }
    // ]))
})

const HtmlWebpackPlugin = require('html-webpack-plugin');
config.plugin("html").use(HtmlWebpackPlugin, [{
    /*
     template 参数指定入口 html 文件路径,插件会把这个文件交给 webpack 去编译,
     webpack 按照正常流程,找到 loaders 中 test 条件匹配的 loader 来编译,那么这里 html-loader 就是匹配的 loader
     html-loader 编译后产生的字符串,会由 html-webpack-plugin 储存为 html 文件到输出目录,默认文件名为 index.html
     可以通过 filename 参数指定输出的文件名
     html-webpack-plugin 也可以不指定 template 参数,它会使用默认的 html 模板。
     */
    template: "./public/index.html",
    filename:"index.html",
    /*
     因为和 webpack 4 的兼容性问题,chunksSortMode 参数需要设置为 none
     https://github.com/jantimon/html-webpack-plugin/issues/870
     */
    chunksSortMode: 'none',
    xhtml: true,
    minify: {
        collapseWhitespace: false, //删除空格,但是不会删除SCRIPT、style和textarea中的空格
        conservativeCollapse: false, //删除空格,总是保留一个空格
        removeAttributeQuotes: false, //删除引号,删除不需要引号的值
        useShortDoctype: false, //使用短的文档类型
        removeComments: true,
        collapseBooleanAttributes: true,
        removeScriptTypeAttributes: true
        // more options:
        // https://github.com/kangax/html-minifier#options-quick-reference
    }
}]);


config.when(isProd,config=>{

}).when(!isProd,config=>{
    config.devServer.host('localhost').port(8080).open(process.os === 'darwin');
})

config.resolve.alias.set("@",path.join(__dirname,"src"));

// Export the completed configuration object to be consumed by webpack
module.exports = config.toConfig();

添加启动脚本

修改package.json文件中scripts节点,加入如下配置:

1
2
3
4
  "scripts": {
    "dev": "cross-env NODE_ENV=development webpack-dev-server",
    "build": "cross-env NODE_ENV=production webpack"
  }

创建postcss.config.js

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
module.exports = {
    plugins: {
        autoprefixer: {
            "browsers": [
                "ie >= 9",
                "ff >= 30",
                "chrome >= 34",
                "safari >= 7",
                "opera >= 23"
            ]
        }
    }
}

创建src/index.js

1
2
3
4
5
export default  class demo {
    constructor(){
        console.log("init");
    }
}

创建example/index.js

1
2
3
import Demo from "../src/index";

const demo = new Demo();

根目录创建index.html

启动

1
yarn run dev