webpack больше не является для нас болевой точкой — основные основы

внешний интерфейс JavaScript Webpack

Webpack всегда был головной болью для фронтенд-инженеров.Из-за его сложности, дисперсии, загрузчика, плагина и других третьих лиц стоимость нашего обучения резко возросла, и мы всегда неоднозначно относились к его конфигурации.Сегодня я покажу как его настроить и избавиться от беды.Наша больная тема давно. Эта статья в основном представляет собой подробное объяснение базовой конфигурации веб-пакета.Чанк модуля, процесс фазы компиляции, процесс фазы вывода, написание загрузчика и рукописный плагин веб-пакета будут запущены в последующих статьях.Чтобы не пропустить, вы можете следовать за мной или добавьте в закладки мой личный блог www.ngaiwe.com

1. Что такое веб-пакет?

WebPack можно рассматривать как упаковщик модулей: он анализирует структуру вашего проекта, находит модули JavaScript и другие языки расширения (Scss, TypeScript и т. д.), которые браузеры не могут запускать напрямую, и упаковывает их в подходящий формат для браузера. использовать. И следуйте вашим различным потребностям в проекте, реализуйте автоматическую обработку и высвобождайте нашу производительность.

  • Преобразование кода: TypeScript компилируется в JavaScript, SCSS компилируется в CSS.
  • Оптимизация файлов: сжатие JavaScript, CSS, HTML-кода, сжатие и объединение изображений и т. д.
  • Разделение кода: извлеките общий код нескольких страниц, извлеките код, который не нужно выполнять на первом экране, и дайте ему загрузиться асинхронно.
  • Слияние модулей: в модульном проекте будет много модулей и файлов, и для классификации и объединения модулей в один файл требуется функция сборки.
  • Автоматическое обновление: отслеживайте изменения локального исходного кода, автоматически перестраивайте и обновляйте браузер.
  • Проверка кода: перед отправкой кода на склад необходимо проверить, соответствует ли код спецификации и проходит ли модульный тест.
  • Автоматический выпуск: после обновления кода код онлайн-релиза создается автоматически и передается в систему выпуска.

2. Инициализация проекта

mkdir webpack-start
cd webpack-start
npm init

3. Основные концепции веб-пакета

  • Вход: Вход, первый шаг построения веб-пакета начнется с входа, который можно абстрактно понимать как ввод.
  • Модуль: модуль, все является модулем в webpacl, модуль соответствует файлу, веб-пакет будет рекурсивно находить все зависимые модули из настроенной записи
  • Чанк: блок кода, фрагмент состоит из нескольких модулей, используемых для объединения и разделения кода.
  • Загрузчик: преобразователь модулей, который используется для преобразования исходного содержимого модуля в новое содержимое, необходимое в соответствии с требованиями.
  • Плагин: плагин расширения, который внедряет логику расширения в определенное время в процессе сборки веб-пакета, чтобы изменить результат сборки и то, что он хочет сделать.
  • Вывод: введите результат, пройдите серию обработок в webpack и получите окончательный желаемый код, а затем выведите результат.

Когда Webpack запустится, он начнется сEntryнастроен вModuleНачать рекурсивный разбор всех модулей, от которых зависит Entry. Каждый раз, когда модуль будет найден, он будет настроен в соответствии сLoaderЧтобы узнать соответствующие правила преобразования, преобразуйте модуль, а затем проанализируйте модуль, от которого зависит текущий модуль. Эти модули будут сгруппированы в единицы Записи, Запись и все зависимые от нее Модули разделены на группу, которая являетсяChunk. Наконец, Webpack преобразует все фрагменты в выходные файлы. В течение всего процесса Webpack будет выполнять логику, определенную в плагине, в нужное время.

1.Entry

Контекст используется, чтобы решить, что файл конфигурации и файл записи больше не находятся в одной и той же структуре уровня.Например, наш файл конфигурации находится в конфигурации, а файл записи находится в корневом каталоге, тогда конфигурация выглядит следующим образом

module.exports = {
  context: path.join(__dirname, '..'), // 找到根目录
  entry: './main.js' //根目录下的入口文件
}

Простейшая одностраничная (SPA) запись, импортируйте main.js и начните синтаксический анализ в соответствии с модулями, на которые ссылаются и которые зависят от main.js.

module.exports = {
  entry: './main.js'
}

Многостраничная (MPA) запись записи, импорт нескольких файлов, конечно, обычно чтение файла записи в указанной папке, а затем импорт

entry: {
  home: "./home.js",
  about: "./about.js",
  contact: "./contact.js"
}

Если это одна страница (передается строка или массив строк), чанк будет называться main, если он многостраничный (передается объект), каждый ключ (key) будет именем чанка, описание точки входа чанка

2.Output

Object инструктирует webpack, как экспортировать и куда экспортировать ваши пакеты, активы и все остальное, что вы связываете или загружаете с помощью webpack.

  • путь: выходной каталог соответствует абсолютному пути

    path: path.resolve(__dirname, 'dist')
    
  • pathinfo: boolean Функция false по умолчанию указывает веб-пакету ввести соответствующие комментарии к информации о модуле, содержащейся в комплекте, которые не следует использовать в производственной среде (производство) и чрезвычайно полезны для среды разработки (разработки).

  • publicPath: основная функция заключается в обработке статического пути к файлу в упакованном файле.

  • имя файла: определяет имя каждого выходного пакета, который будет записан в каталог, указанный параметром output.path.Для одиночной записи имя файла является статическим именем

    filename: "bundle.js"
    

    Но в веб-пакете мы будем использовать разделение кода, различные плагины-плагины или вход с несколькими входами для создания нескольких пакетов, поэтому мы должны дать каждому пакету уникальное имя.

    filename: "[name].bundle.js"
    

    использовать внутренний идентификатор чанка

    filename: "[id].bundle.js"
    

    Генерация уникального хэша

    filename: "[name].[hash].bundle.js"
    

    Используйте хэш на основе содержимого каждого фрагмента

    filename: "[chunkhash].bundle.js"
    
3.Модульный модуль

Обработка различных модулей, применяемых в проекте, основная конфигурация находится в Правилах, соответствующих запрошенному массиву правил, эти правила могут применять загрузчик к модулю или модифицировать парсер парсера

  • Module.noParse: не позволяет веб-пакету анализировать файлы, которые успешно соответствуют правилам, и игнорировать большие библиотеки для оптимизации производительности.Игнорируемые файлы не должны содержать вызовы для импорта, требования и определения

    module.exports = {
      module: {
        rules: [],
        noParse: function(content) {
          return /jquery|lodash/.test(content) // 忽略jquery文件解析,直接编译打包
        }
      }
    }
    
  • Правила: при создании модуля массив правил, соответствующих запросу

    • Условия правила: ресурс (абсолютный путь запрашиваемого файла), эмитент (абсолютный путь файла модуля запрашиваемого ресурса, расположение при импорте), например, файл А импортирует файл Б, ресурс /B, эмитент / A — это файл импорта Вместо реального местоположения в правиле test/include/exclude/resource соответствует ресурсу, а эмитент соответствует только эмитенту.

    • Использование и отличие Test/include/exclude/resource/issuer

      module.exports = {
          modules: {
              rules: [
                {
                  test: /\.js?$/,
                  include: [
                    path.resolve(__dirname, "app")
                  ],
                  exclude: [
                    path.resolve(__dirname, "app/demo")
                  ],
                  resource:{
                    test: /\.js?$/,
                    include: path.resolve(__dirname, "app"),
                    exclude: path.resolve(__dirname, "app/demo")
                  },
                  issuer: {
                    test: /\.js?$/,
                    include: path.resolve(__dirname, "app"),
                    exclude: path.resolve(__dirname, "app/demo")
                  }
                }
              ]
        }
      }
      

      test: Как правило, предоставляется регулярное выражение или массив регулярных выражений.Если абсолютный путь соответствует этому регулярному выражению, это означает, что это условие выполнено.

      include: это строка или массив строк, файлы в указанном каталоге должны следовать этому правилу

      exclude: также является строкой или массивом строк, файлы в указанном каталоге не должны следовать этому правилу.

      ресурс: это обёртка для text/include/exclude, которая ничем не отличается от написания их по отдельности

      эмитент: имеет ту же функцию, что и ресурс, но разница в том, что он применяет правило к какому файлу и ко всем зависимым файлам, импортируемым этим файлом

    • RecounceQuery: то же самое то же самое, что и ресурс, но это параметр PATH для соответствующего результата «?» Вы можете вызвать текст в ресурсе и т. Д.

    • oneOf: указывает, что к ресурсу применяется только первое правило сопоставления, обычно в сочетании с resourceQuery.

      {
        test: /\.(png|jpe?g|gif|svg)$/,
        oneOf: [
          {
            resourceQuery: /inline/, 
            loader: 'url-loader'
          },
          {
            loader: 'file-loader'
          }
        ]
      }
      
      • path/to/foo.png?inline: будет соответствовать url-loader
      • path/to/foo.png?other: будет соответствовать файловому загрузчику
      • path/to/foo.png: будет соответствовать файловому загрузчику
    • useEntry: объект содержит каждый загрузчик и соответствует файлу конфигурации загрузчика

      {
        loader: "css-loader",
        options: {
          modules: true
        }
      }
      

      параметры будут переданы в загрузчик, что можно понимать как параметры загрузчика

    • use: представляет собой набор useEntry и указывает использование загрузчика для каждой записи.

      use: [
        'style-loader',
        {
          loader: 'css-loader',
          options: {
            importLoaders: 1
          }
        },
        {
          loader: 'less-loader',
          options: {
            noIeCompat: true
          }
        }
      ]
      
4.Анализ решения

В основном используется для анализа модулей, предоставляя значения по умолчанию для веб-пакета.

  • псевдоним: объект в основном используется для более удобного импорта и вызовов require, а также для установки начального пути

    module.exports = {
     alias: {
      Utilities: path.resolve(__dirname, 'src/utilities/'),
      Templates: path.resolve(__dirname, 'src/templates/')
     }   
    }
    // 最开始的import
    import Utility from '../../utilities/utility';
    // 配置完以后
    import Utility from 'Utilities/utility';
    
  • forceExtension: Boolean Значение по умолчанию — false, что означает, что ссылка не нуждается в расширении.Если это правда, ссылка в импорте и запросе должна добавить расширение

  • extensions: автоматический разбор массива не требует расширений

    extensions: [".js", ".json"]  // .js、.json引入不需要扩展名
    
  • модули: каталог, в котором веб-пакет Array должен искать при разборе модулей, обычно используется для первого поиска и пользовательских модулей в файлах, отличных от node_modules.

    modules: [path.resolve(__dirname, "src"), "node_modules"] //优先搜索src目录
    
5.Loader

Используя разные загрузчики, Webpack может конвертировать разные файлы в файлы JS, такие как CSS, ES6/7, JSX и т. д., которые обычно используются при использовании модулей.

module: {
  rules:[
      {
        test:/\.css$/,
        use:['style-loader','css-loader'],
        include:path.join(__dirname,'./src'),
        exclude:/node_modules/
      }
  ]      
}

Для конкретных связанных загрузчиков вам необходимо проверить официальный документ API загрузчика, который вы хотите представить.Рукописный загрузчик будет представлен в следующей статье.

6. Плагин

Массив расширяет веб-пакет и внедряет логику расширения в определенное время в процессе сборки веб-пакета, чтобы изменить результат сборки и то, что вы хотите сделать. Проверьте официальную документацию плагина, который вы представили для конкретного использования. Рукописный плагин будет запущен в следующих статьях. .

7.webpack-dev-server

Сервер в стадии разработки, webpack-dev-server может быстро создать локальную службу, см. конкретное использованиеwebpack-dev-server

8.Devtool

Этот параметр определяет, следует ли генерировать и как генерировать официально рекомендованныеSourceMapDevToolPluginа такжеsource-map-loaderРекомендуется прочитать официальную документациюDevtoolОн в основном используется для контроля качества упаковки, простоты отладки в среде разработки и скорости компиляции.

9.Watch

webpack может отслеживать файлы на предмет изменений, перекомпилировать и перекомпилировать при их измененииHotModuleReplacementPluginЕсть сходства, слушайте изменения файлов и теплый старт

4. Настройте веб-пакет

команда установки веб-пакета

npm install webpack webpack-cli -D

Webpack.config.js

Используемый конкретный плагин

  • clean-webpack-plugin: используется для очистки выходного каталога перед упаковкойОфициальный API
  • html-webpack-plugin: используется для автоматического создания HTML и ссылки на сгенерированные ресурсы.Официальный API
  • copy-webpack-plugin: используется для копирования статических ресурсов, включая ресурсы без ссылок.Официальный API
  • uglifyjs-webpack-plugin: используется для сжатия JS, выходной JS-файл может быть меньше по размеру, быстрее загружаться, меньше трафика и с функцией шифрования запутанного кода.Официальный API
  • Extract-text-webpack-plugin: Поскольку загрузка CSS и JS может выполняться параллельно, когда файл HTML очень большой, мы можем извлечь CSS отдельно и загрузить его.Официальный API
const path = require('path');
const webpack = require('webpack');
const CleanWebpackPlugin = require('clean-webpack-plugin');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const CopyWebpackPlugin = require('copy-webpack-plugin');
const UglifyjsWebpackPlugin = require('uglifyjs-webpack-plugin')
// npm i extract-text-webpack-plugin@next // @next可以安装下一个非正式版本
const ExtractTextWebpackPlugin = require('extract-text-webpack-plugin');
let cssExtract = new ExtractTextWebpackPlugin({
    filename: 'css/css.css',
    allChunks: true
});
let lessExtract = new ExtractTextWebpackPlugin('css/less.css');
let sassExtract = new ExtractTextWebpackPlugin('css/sass.css');
/**
 * 有些时候我们希望把页面中的CSS文件单独拉出来保存加载
 * extract-text-webpack-plugin
 */
//let pages = ['index', 'base'];
// pages = pages.map(page => new HtmlWebpackPlugin({
//     template: './src/index.html',//指定产的HTML模板
//     filename: `${page}.html`,//产出的HTML文件名
//     title: `${page}`,
//     chunks: ['common', `${page}`],//在产出的HTML文件里引入哪些代码块
//     hash: true,// 会在引入的js里加入查询字符串避免缓存,
//     minify: {
//         removeAttributeQuotes: true
//     }
// }));
module.exports = {
    //先找到每个入口(Entry),然后从各个入口分别出发,找到依赖的模块(Module),
    //然后生成一个Chunk(代码块),最后会把Chunk写到文件系统中(Assets)   
    entry: './src/main.js',
    output: {
        path: path.join(__dirname, 'dist'),//输出的文件夹,只能是绝对路径 
        //name是entry名字main,hash根据打包后的文件内容计算出来的一个hash值
        filename: '[name].[hash].js' //打包后的文件名
    },
    resolve: {
        //引入模块的时候,可以不用扩展名 
        extensions: [".js", ".less", ".json"],
        alias: {//别名
            "bootstrap": "bootstrap/dist/css/bootstrap.css"
        }
    },
    //表示监控源文件的变化,当源文件发生改变后,则重新打包
    watch: false,
    watchOptions: {
        ignored: /node_modules/,
        poll: 1000,//每秒钟询问的次数
        aggregateTimeout: 500//
    },
    //devtool: 'source-map',//单独文件,可以定位到哪一列出错了
    // devtool: 'cheap-module-source-map',//单独文件,体积更小,但只能定位到哪一行出错
    // devtool: 'eval-source-map',//不会生成单独文件,
    // devtool: 'cheap-module-eval-source-map',//不会生成单独文件 只定位到行,体积更小
    /*
    loader有三种写法
    use
    loader
    use+loader
    * */
    module: {
        rules: [
            {
                test: require.resolve('jquery'),
                use: {
                    loader: 'expose-loader',
                    options: '$'
                }
            },
            {
                test: /\.js/,
                use: {
                    loader: 'babel-loader',
                    query: {
                        presets: ["env", "stage-0", "react"]
                    }
                }
            },
            {
                //file-loader是解析图片地址,把图片从源位置拷贝到目标位置并且修改原引用地址
                //可以处理任意的二进制,bootstrap 里字体
                //url-loader可以在文件比较小的时候,直接变成base64字符串内嵌到页面中
                test: /\.(png|jpg|gif|svg|bmp|eot|woff|woff2|ttf)/,
                loader: {
                    loader: 'url-loader',
                    options: {
                        limit: 5 * 1024,
                        //指定拷贝文件的输出目录 
                        outputPath: 'images/'
                    }
                }
            },
            {
                test: /\.css$/,//转换文件的匹配正则
                //css-loader用来解析处理CSS文件中的url路径,要把CSS文件变成一个模块
                //style-loader 可以把CSS文件变成style标签插入head中
                //多个loader是有顺序要求的,从右往左写,因为转换的时候是从右往左转换
                //此插件先用css-loader处理一下css文件
                //如果压缩
                loader: cssExtract.extract({
                    use: ["css-loader?minimize"]
                })
                //loader: ["style-loader", "css-loader", "postcss-loader"]
            },
            {
                test: /\.less$/,
                loader: lessExtract.extract({
                    use: ["css-loader?minimize", "less-loader"]
                })
                //use: ["style-loader", "css-loader", "less-loader"]
            },
            {
                test: /\.scss$/,
                loader: sassExtract.extract({
                    use: ["css-loader?minimize", "sass-loader"]
                })
                // use: ["style-loader", "css-loader", "sass-loader"]
            },
            {
                test: /\.(html|htm)/,
                loader: 'html-withimg-loader'
            }
        ]
    },
    plugins: [
        //用来自动向模块内部注入变量
        // new webpack.ProvidePlugin({
        //     $: 'jquery'
        // }),
        new UglifyjsWebpackPlugin(),
        new CleanWebpackPlugin([path.join(__dirname, 'dist')]),
        //此插件可以自动产出html文件
        new HtmlWebpackPlugin({
            template: './src/index.html',//指定产的HTML模板
            filename: `index.html`,//产出的HTML文件名
            title: 'index',
            hash: true,// 会在引入的js里加入查询字符串避免缓存,
            minify: {
                removeAttributeQuotes: true
            }
        }),
        new CopyWebpackPlugin([{
            from: path.join(__dirname, 'public'),
            to: path.join(__dirname, 'dist', 'public')
        }]),
        cssExtract,
        lessExtract,
        sassExtract
    ],
    //配置此静态文件服务器,可以用来预览打包后项目
    devServer: {
        contentBase: './dist',
        host: 'localhost',
        port: 8000,
        compress: true,//服务器返回给浏览器的时候是否启动gzip压缩
    }
}

5. Резюме

Эта статья является более базовой и может создать простую конфигурацию веб-пакета. Расширенные и расширенные будут представлены в последующих статьях, и я надеюсь, что вы больше прочитаете официальный API, а затем подведете итоги самостоятельно. Только экспортируя знания, вы сможете лучше запомнить и учить.

6. Блог

Технологический блог Вэй Ран

Если у вас есть какие-либо вопросы, оставьте сообщение или отправьте письмо по адресу ngaiwe@126.com.