Coder Social home page Coder Social logo

mcler / webpack-concat-plugin Goto Github PK

View Code? Open in Web Editor NEW

This project forked from hxlniada/webpack-concat-plugin

10.0 2.0 8.0 1.13 MB

a plugin to help webpack to concat file and inject to html

Home Page: https://github.com/mcler/webpack-concat-plugin

JavaScript 96.66% HTML 1.89% EJS 1.45%

webpack-concat-plugin's Introduction

@mcler/webpack-concat-plugin

npm package

A plugin to concat static JavaScript files and (optionally) inject into HTML without Webpack’ JSONP code wrapper. A perfect solution for bundling legacy code.

It delivers:

  • Concatination of files
  • Source maps
  • Minification
  • Support for webpack@5 and html-webpack-plugin@5
  • Inject to HTML (via html-webpack-plugin)

Only Webpack 5 is supported

Forked from hxlniada’s plugin – supports Webpack 4

Install

npm install @mcler/webpack-concat-plugin --save-dev
yarn add @mcler/webpack-concat-plugin --dev

Use

const ConcatPlugin = require('@mcler/webpack-concat-plugin');
new ConcatPlugin({
  name: 'result',
  outputPath: 'path/to/output/',
  fileName: '[name].[hash:8].js',
  filesToConcat: [
    'jquery',
    './src/lib/**',
    './dep/dep.js',
    [
      './some/**',
      '!./some/excludes/**'
    ]
  ],
  attributes: {
    async: true
  }
});

Minification and Source maps

Key difference of this plugin from original version is use of Webpack mechanisms for minification and creating source maps.

webpack.config.js mode option

module.exports = {
  // skipping full config...
  mode: 'production'
};

webpack.config.js detailed configuration

module.exports = {
  // skipping full config...
  optimization: {
    minimize: true,
    minimizer: new TerserPlugin(), // or anything you like
  },
  devtool: 'source-map'
};

Options

name

string = "result"

Output chunk name.

publicPath

string | false = webpack.publicPath

Public path to asset. If publicPath is set to false, then relativePath will be used. publicPath will affect script tags:

<script src="{publicPath}/{fileName}" />

outputPath

string = ""

Output directory of the file.

fileName

string = "[name].js"

Output file name.

filesToConcat required

string[]

Array of file paths to concat. Supported path patterns:

  • normal path
  • npm packages
  • glob patterns

injectType

string = "prepend": "prepend" | "append" | "none"

How to inject script tags (only works if html-webpack-plugin has inject option set to false)

attributes

Record<string, boolean | string>

Extra attributes applied to script tag.

{
  async: false,
  defer: true,
  crossorigin: "anonymous"
}

Examples

Manual inject into HTML

<script src="<%= htmlWebpackPlugin.files.webpackConcat.file %>"></script>

webpack-concat-plugin's People

Contributors

davidzhaozz avatar ddumont avatar filipesilva avatar gosp avatar hxlniada avatar indragunawan avatar jiverson avatar karlalnebratt avatar mcler avatar mrusselltombras avatar subhaze avatar tomastrajan avatar xcatliu avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

webpack-concat-plugin's Issues

Existing source maps of concatenated scripts are ignored

If input files has source maps besides them, then they should also be merged. For example when concatenating of two minified libraries.
To support source maps I overrode existing class (v4.1.4) that way:

import { readFile } from 'fs/promises';
import { relative } from 'upath';
import { ConcatSource, OriginalSource, SourceMapSource } from 'webpack-sources'
import { Compilation, Compiler } from 'webpack';
import type { RawSourceMap } from 'source-map';

import ConcatPlugin = require('@mcler/webpack-concat-plugin');

class FileWithMap {
    constructor(private readonly _content: string, private readonly _sourceMap: RawSourceMap) {
    }

    public get sourceMap() {
        return this._sourceMap;
    }

    public toString() {
        return this._content;
    }
}

const originalResolve = ConcatPlugin.prototype.resolveReadFiles;
ConcatPlugin.prototype.resolveReadFiles = function (compiler: Compiler): void {
    originalResolve.call(this, compiler);

    let readFilePromise: ReturnType<typeof createSourcesPromise>;

    this.getReadFilePromise = (createNew: boolean) => {
        if (!readFilePromise || createNew) {
            readFilePromise = createSourcesPromise.call(this);
        }

        return readFilePromise;
    };

    async function getSourceAndMap(filePath: string) {
        const path = `webpack:///${relative(compiler.options.context, filePath)}`;
        const source = await readFile(filePath);
        const sourceMap = await readSourceMap(filePath);

        return {
            [path]: new FileWithMap(source.toString(), sourceMap)
        };
    }

    async function readSourceMap(filePath: string) {
        try {
            const sourceMapText = await readFile(filePath + '.map');
            return JSON.parse(sourceMapText.toString()) as RawSourceMap;
        } catch (error) {
            console.debug(`Skip reading source map for '${filePath}'. Details: ${error.message}`);
            return undefined;
        }
    }

    async function createSourcesPromise() {
        this.needCreateNewFile = true;
        const filePathArray: string[] = await this.filesToConcatAbsolutePromise;

        return await Promise.all(filePathArray.map((path) => getSourceAndMap(path)));
    };
}

ConcatPlugin.prototype.resolveConcatAndUglify = function (compilation: Compilation, files: { [x: string]: FileWithMap }[]): void {
    const allFiles = files.reduce((file1, file2) => Object.assign(file1, file2), {});
    this.finalFileName = this.getFileName(allFiles);
    const concatSource = new ConcatSource();
    Object.entries(allFiles).forEach(([name, file]) => {
        const fileContent = file.toString();
        const source = file.sourceMap
            ? new SourceMapSource(fileContent, name, file.sourceMap)
            : new OriginalSource(fileContent, name);
        concatSource.add(source);
        concatSource.add('\n');
    });
    compilation.emitAsset(this.finalFileName, concatSource);
    this.needCreateNewFile = false;
}

export = ConcatPlugin;

If you interested in including this functionality in the library I can create PR (or your can merge it yourself).

P.S. It also fixes problem with missing newline between merged scripts.

Babel not processing concated files

I don't know if I am missing something, but it appears as if Babel is not processing the concated results of this plugin.

Is there a way to transform concated code?

glob-parent dependency vulnerability

Hi,

Any chance you fix this glob-parent vulnerability? 'globby' needs to be bumped.

GHSA-ww39-953v-wcq6

@mcler/webpack-concat-plugin: 4.1.5 -> globby: ^8.0.1 -> fast-glob: ^2.0.2 -> glob-parent: ^3.1.0

image

This is the only vulnerability I cannot fix in my project, this has been the case for quite some time.

Thanks!

order of files to concat is not preserved in output

It seems that with this plugin, the order of my files is not preserved as I specify them in filesToConcat. This used to work with the old webpack4 plugin. The files in the final bundle appear to be ordered alphabetically (backbone, bootstrap, clusterize, countUp, etc...).

This is a problem for me because I am building a bundle out of bootstrap and jquery. bootstrap has a top-level check for jQuery's existence, and blows up if it can't find it. Even though I have jQuery as the first file listed in filesToConcat, it is not the first module in the output file.

I traced the code a bit and tried to fix it. resolveConcatAndUglify is losing the order of the files by merging them all into one object and then iterating over the keys of the object with Object.entries(allFiles).forEach(...) while adding sources to the ConcatSource. I changed it to iterate over the original files to maintain the order:

  resolveConcatAndUglify(compilation, files) {
    const allFiles = files.reduce((acc, file) => Object.assign(acc, file), {});
    this.finalFileName = this.getFileName(allFiles);
    const concatSource = new ConcatSource();
    for (const fileObj of files) {
      const name = Object.keys(fileObj)[0];
      const file = fileObj[name];
      concatSource.add(new OriginalSource(file, name));
    }
    compilation.emitAsset(`${this.settings.outputPath}/${this.finalFileName}`, concatSource);
    this.needCreateNewFile = false;
  }

Unfortunately the final build is still not ordered correctly, so I'm not sure what else to do.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.