@codecoupler/cc-webpack
CodeCoupler Webpack Configuration Factory
Last updated 6 days ago by tom27 .
MIT · Original npm · Tarball · package.json
$ cnpm install @codecoupler/cc-webpack 
SYNC missed versions from official npm registry.

Webpack Toolchain for authoring libraries in JavaScript and TypeScript

What is this

cc-webpack is a compilation of Webpack libaries fine-tuned to each other to start writing libraries in modern JavaScript, TypeScript and CSS without having to worry about linting, compiling and transpiling.

cc-webpack can be added to each project and will provide a command line interface invoked with cc-webpack [options]. However, it is highly recommended to initialize a cc-webpack project with npm init cc-webpack. This will create a boilerplate which include some important configuration files to exploit the full potential of cc-webpack.

Basic configuration

cc-webpack will generate and use a webpack configuration on the fly which can be configured in a file named webpack.cc-config.js. If you use a Webpack configuration file webpack.config.js the both configurations will be smart-merged.

Recommended VSCode Setup

cc-webpack will lint and fix JavaScript and TypeScript files by ESLint and Prettier, Stylesheet files by styellint. The integrated boilerplate will will generate the needed configuration files which make VSCode to lint these files on save. To make this work you have to install the following extensions:

This extension is also recommended but not mandatory:

Getting Started

Start without the integrated Boilerplate

cd to/your/existing/project
npm i webpack -D # If not already done
npm i @codecoupler/cc-webpack -D

Start with integrated Boilerplate (Recommended)

mkdir new-project-folder
cd new-project-folder
npm init @codecoupler/cc-webpack
npm i

Before start working with this boilerplate the following fields should be set in package.json (read the documentation):

  • name
  • version
  • description
  • author (You could reference here to the AUTHORS file)
  • homepage
  • keywords
  • license
  • private (Remove it if this project should be public)

Then you could change the title of static/index.html and overwrite static/logo.png with your own logo.

Last but not least the file LICENSE and the file AUTHORS should be updated.

Start Writing Code

Now you can start writing your code in the folder src and put asset files into the folder static. You can organize the files inside these folders as always you want.

A last important Note: Do not put anything into the folder dist. This folder will wiped everytime you compile. Use only the folders src and static.

What You Get

Build Results of JS and TS Files

All *.js and *.ts files within the folder src will be bundled in one file into the dist folder. The name specified in the package.json will be used as filename. You can also change the filename in the file webpack.cc-config.js (bundle.jsName).

You can use modern ES6 syntax and use the ES6 modules standard in all of your JavaScript and TypeScript files.

JavaScript and TypeScript files will be linted (ESLint), format checked (Prettier), type checked if needed (typescript), compiled to run on targeted browsers that are specified in .browserlistrc., mangled and minimized (terser) and finally a Source Map file will be created.

Build Results of CSS Files

All required CSS files will be bundled in one file into the dist folder. The name specified in the package.json will be used as filename. You can also change the filename in the webpack.cc-config.js (bundle.cssName). To require a CSS file just put an import "./path/to/your/file.css"; in any of your JavaScript or TypeScript files.

You can use modern and pure CSS without thinking about vendor prefixes or browser inconsistencies.

Your CSS will be converted and extended with polyfills (postcss-preset-env) and vendor prefixes (autoprefixer) based on your targeted browsers specified in .browserlistrc, optimized and minimized (cssnano) and finally a Source Map file will be created.

Read more about all the modern CSS you can use here: preset-env

Note: Reference to images in the static folder with url() statements like they would be in the same folder. For example to reference to logo.png in the root of the folder static you have to write url(logo.png)

Build Results of VUE Files

You can use .vue files in the src folder which will be compiled into your final .js and .css files. You can use standard JavaScript inside of the script tag or class style TypeScript vue instances Documentation.

Note: The style tag must not specified with with the lang attribute to use modern CSS. It will always be parsed like any other CSS file (read above).

Build Results of HTML Files

You can place HTML files inside the src folder and include them content in two ways. You can bundle them into the resulting JavaScript file, or keep them in seperate files and load them dynamically if needed. The second method keeps your bundled JavaScript file smaller, but it needs an additional configuration on the part of the user of your library.

Please note that if you write libraries that will be published as node modules and afterwards included by cc-webpack-externals-plugin you should not load the HTML content dynamically. In this case it is better to bundle the HTML files into your library. Even if this were possible, it requires some work to include your library, which makes the whole thing unnecessarily complicated.

Bundle into the JavaScript File

All HTML files will be included in the final JavaScript bundle if you require them with import htmlText from "./path/to/your/file.html"; in any of your JavaScript or TypeScript files. You can access to the content of the HTML file via the variable defined in this import statement.

Load them dynamically from separate files

You can use the following syntax to load an HTML file dynamically:

import(
  /* webpackChunkName: "filename.html" */ "./path/to/your/filename.html"
).then((htmlText) => {
  console.info(htmlText.default);
});
  • The name after webChunkName in the "webpack magic comment" will be used as basename for the separate file. It is advisable to use the same name as the HTML file.
  • Please note how to get the content of the HTML file by reading the field .default.

All separated files will be saved in a subdirectory of the dist folder. The name of this subfolder is by default parts. You can change this name in the webpack.cc-config.js (bundle.chunkSubfolder).

If you deploy your library the end user will place the files of course wherever he wants. Therefore your library has to know from where to load the separated files. The user of the library must define the path to your library as follows:

<script>
  window.pathToYourLibrary = "path/to/your/library/";
</script>
<link href="your-library.css" rel="stylesheet" type="text/css" />
<script src="your-library.js" type="text/javascript"></script>

The name pathToYourLibrary is defined in the webpack.cc-config.js. By default it is the package name from the package.json converted into camel case (removing dashes, underscores, dots and tilde) and prefixed by pathTo. Please note the trailing slash that has to be defined.

Build Result of Static Assets

All files within the folder static will be copied to the build result in the dist folder. Here is the best place to write your demo or test pages, your documentation or add some external assets.

Note: The perfomance hints of webpack will be disabled for all files that will be copied from the dist folder.

The following files will be processed in a special way:

HTML Files

HTML files in this directory will be parsed and links to your final JavaScript and Stylesheet files and your external libraries will be injected as script and link tags. Furthermore the resulting HTML will be minified.

What HTML files exactly will be parsed is defined in webpack.cc-config.js (staticParser.htmlTemplates). By default all *.html files will be parsed.

The tags will be placed in the head and body section. If you need to place them in other positions you must disable the inject feature in the webpack.cc-config.js (staticParser.htmlInject) and use the following placeholders:

<%= htmlWebpackPlugin.tags.headTags %>
<%= htmlWebpackPlugin.tags.bodyTags %>

Read more about custom insertion.

Favicons

By default the file logo.png from the static folder will be converted in all possible favorite icons formats (android, appleIcon, appleStartup, coast, favicons, firefox, windows, yandex) and saved in a subdirectory named favicon. The necessary HTML will be injected into the HTML files (see above).

You can adjust the name of the file in webpack.cc-config.js (staticParser.favicon) or disable this feature complete if you set the field to null.

By default the source favicon file will be copied to the dist folder. If you do not need the file after favicon creation you can controll this behaviour in the webpack.cc-config.js (staticparser.keepFaviconSource).

Handling External Libraries

To use external libraries you have to install them with npm --save install PACKAGENAME and import or require them in your code. Doing this the libraries will be included in your bundle. You should always consider to exclude them from your bundle and load them from a local file or a CDN.

To do this you can define this modules in the webpack.externals.js. With these settings modules will not be bundled but copied to a subdirectory vendor in your dist folder. All HTML files from your static folder will be injected with the a matching link or style tag.

To define a module you have to add an object with the following properties to the array:

  • module: The name of the node module.
  • global: Optional. The global variable name to access the library provided by the node module.
  • entries: String or array of strings. Name of js or css files to copy to dist folder and inject into HTML files.
  • copy: String or array of strings. Globs to copy to dist folder.

You can read the documentation of the cc-webpack-externals-plugin to learn more about the configuration options. You do not have to install this plugin, you can use an webpack.externals.js file right away.

[https://www.npmjs.com/package/@codecoupler/cc-webpack-externals-plugin#the-configuration-file](The configuration file)

Furthermore you can build a version where the modules will not copied and the tags will point to a CDN (see below "How to Build").

How to Build

Production Build

npm run build (if using the boilerplate)
npx cc-webpack --mode production (use without boilerplate)

This command will build the final JavaScript library, the Stylesheet File and copy and process the files from the static folder. All minified, mangled and with source maps in separate files.

You can setup some parameters in the webpack.cc-config.js for the production build:

  • production.stripFunctions: Array of function names (strings) that will be removed from your source code. Usefull to eliminate debuging calls like console.debug. The default webpack.cc-config.js will strip out console.debug for example.

  • production.banner: Banner to add to your final JavaScript file. Usefull for licence and version informations. The default webpack.cc-config.js contains an example which extracts the most important informations from package.json.

npm run build:watch (if using the boilerplate)
npx cc-webpack --watch --mode production (use without boilerplate)

This command will stay after the production build in the watch mode and will recompile whenever a source file is changed.

Development Environment

The following commands will build the library in development mode. Some features will be disabled for better compiling perfomance and easier debuging:

  • JavaScript, CSS and HTML will not minified or mangled.
  • SourceMaps will be inlined.
  • Only one simple favicon will be created.

npm start (if using the boilerplate)
npx cc-webpack --devserver --mode development (use without boilerplate)

This will build the library, start the webpack development server and the browser pointing to the server. Everytime you modify your code the page will be automatically reloaded.

You will not see the building results in the dist folder, because the the server keeps bundle files in memory and serves them as if they were real files mounted at the server's root path.

Within this environment you can develop your library.

npm run watch (if using the boilerplate)
npx cc-webpack --watch --mode development (use without boilerplate)

This will build the library and save the results in the dist folder. Everytime you modify your code the compilation will start automatically again.

You can use this environment if you have to use another server then the webpack development server.

npm run build:dev (if using the boilerplate)
npx cc-webpack --mode development (use without boilerplate)

This will build the library and save the results in the dist folder. Nothing more.

CDN Versions

You can build your code to include CDN links to your external modules instead of copying to the dist folder with these commands:

npm run start:cdn (if using the boilerplate)
npx cc-webpack --devserver --externals-cdn --mode development (use without boilerplate)

Development Server running with CDN build.

npm run watch:cdn (if using the boilerplate)
npx cc-webpack --watch --externals-cdn --mode development (use without boilerplate)

Watching mode with CDN build.

npm run build:dev:cdn (if using the boilerplate)
npx cc-webpack --externals-cdn --mode development (use without boilerplate)

Just build a CDN version in development mode.

npm run build:cdn (if using the boilerplate)
npx cc-webpack --externals-cdn --mode production (use without boilerplate)

Final production CDN build.

npm run build:watch:cdn (if using the boilerplate)
npx cc-webpack --watch --externals-cdn --mode production (use without boilerplate)

Watching mode with final production CDN build.

Linting Tools

npm run lint (if using the boilerplate)
tsc --noEmit && eslint ./src/**/*.{js,ts} --quiet && npx stylelint ./src/**/*.css (use without boilerplate)

This command will first run the TypeScript compiler and report any TypeScript compiler errors. If there are no TypeScript errors, it will then run ESLint through all the .js and .ts files in the src folder. If there are no ESLint errors, it will then run stylelint through all the .css files in the src folder. Any errors will be printed out in the command line.

npm run lint:fix (if using the boilerplate)
tsc --noEmit && eslint ./src/**/*.{js,ts} --quiet --fix && npx stylelint ./src/**/*.css --fix (use without boilerplate)

This command is the same as npm run dev:lint. But any ESLint and stylelint errors that can be automatically fixed will be fixed with this command, but any other errors will be printed out in the command line. Any TypeScript or ESLint error will stop further execution.

npm run lint:light or npm run lint:light:fix (if using the boilerplate)
eslint ./src/**/*.{js,ts} --quiet [--fix] && npx stylelint ./src/**/*.css [--fix] (use without boilerplate)\

These both commands works exactly like npm run lint and npm run lint:fix but without the TypeScript compiler. Usefull for projects without TypeScript files because the TypeScript complier throws an error if no TypeScript files was found.

npm run tslint or npm run tslint:fix (if using the boilerplate)
tsc --noEmit && eslint ./src/**/*.ts --quiet [--fix] (use without boilerplate)\

These both commands run only the TypeScript compiler and report any TypeScript compiler errors. If there are no TypeScript errors, it will then run ESLint through all the .ts files in the src folder.

npm run jslint or npm run jslint:fix (if using the boilerplate)
eslint ./src/**/*.js --quiet [--fix] (use without boilerplate)\

These both commands run only ESLint through all the .js files in the src folder.

npm run csslint or npm run csslint:fix (if using the boilerplate)
npx stylelint ./src/**/*.css [--fix] (use without boilerplate)\

These both commands run only stylelint through all the .css files in the src folder.

Debuging cc-webpack

npm run test:cc-webpack or npm run test:cc-webpack:dev (if using the boilerplate)
npx cc-webpack --test [--mode production] (use without boilerplate)\

This will print the Webpack configuration generated by cc-webpack and some other details.

Repositories Integration

Using the boilerplate will include some configurations which handle the GIT and the NPM repositories:

GIT

GIT commits will ignore the dist, the node_modules folder and any packages generated by npm pack.

Before any commit, staged .ts, .js and .css files inside the src folder will be checked by the associated linter. If any of these checks fail (process exits with non-zero code), the commit will be aborted.

NPM

To prevent an accidental publish the package is marked as private. If you want to publish you have to remove this from the package.json.

Now it's important to decide if you want to publish just your library, or an entire web application

Then npm publish will publish by default only:

  • All .css, .css.map, .js and .js.map files from the dist folder.
  • The subdirectory parts in the dist folder.
  • The webpack.externals.js file.
  • The LICENSE file.
  • The AUTHORS file

If you gonna publish an entire web application you should change the files directive in package.json to:

{
  "files": [
    "dist/"
  ],
}

Configuration Reference

In the webpack.cc-config.js you can define some paramaters to adjust the base cc-webpack configuration.

module.exports = {
  bundle: {
    //  Name of the bundled JavaScript file
    //  Default: Package name from package.json without scope
    jsName: "string",

    //  Name of the bundled Stylesheet file
    //  Default: Package name from package.json without scope
    cssName: "string",

    //  Variablename where to find the publicPath in runtime
    //  Default: Package name from package.json without scope converted into camel case and prefixed
    //           with "pathTo"
    //  Example:
    //    Packagename: @some-scope/name-with_underscoder~and~tilde
    //    Result: pathToNameWithUnderscoreAndTilde
    pathVarName: "string",

    //  Subfolder where chunks for dynamic imports will be saved
    //  Default: "parts"
    chunkSubfolder: "string"

    //  Function to convert the local paths of "externals" to a CDN link.
    //
    //  Default: (name, version, path) => `//cdn.jsdelivr.net/npm/${name}@${version}/${path}`
    //
    //  Example for using unpkg: (name, version, path) => "//unpkg.com/${name}@${version}/${path}"
    getCdnPath: function
  },
  staticParser: {
    //  Array of relative paths to HTML files in static folder which should be parsed
    //  Default: Result of glob **/*.html
    htmlTemplates: ["string", "string"],

    //  If "true" the tags for including the final bundle and external JavaScript and
    //  Stylesheet files will be injected into the html templates.
    //  Default: true
    htmlInject: Boolean

    //  Filename or relative path of source image for favicon creation
    //  Default: "logo.png"
    favicon: "string",

    //  If true the source image of the favicons will be copied into the dist folder.
    //  Default: true
    keepFaviconSource: Boolean
  },
  production: {
    //  Array of funtion names should be removed in the production build
    //  Default: ["console.debug"]
    stripFunctions: ["string","string"],

    //  Banner to add into your build result
    //  Default: ${PACKAGE.name} ${PACKAGE.version}
    //           Copyright (c) ${new Date().getFullYear()} ${PACKAGE.author}
    //           License: ${PACKAGE.license}`
    banner: "string"
  },
};

Detailed Documentation

If you want to know what all the configuration files of the the integrated boilerplate are for a meaning you should read Details of all Files.

The generated and used Webpack configuration works as follows:

{
  // The assetFilter mute the perfomance counter for static assets,
  // favicons and external libraries:
  performance: { assetFilter: [Function: assetFilter] },

  // To keep the code clean we should import all other filetypes
  // including their extensions:
  resolve: {
    extensions: [ '.js', '.ts' ]
  },

  // Use the arguments to define mode and source-map generation
  mode: args.mode || "development",
  devtool: args.mode == "production" ? "source-map" : "eval-source-map",

  // Parse every js and ts file and bundle in one file.
  // The chunkFilename is defined for dynamic imports:
  entry: glob.sync("./src/**/*.@(js|ts)"),
  output: {
    filename: 'my-library.js',
    chunkFilename: 'parts/[name].js',
    path: path.join(process.cwd(), "dist")
  },

  // This is the default configuration of the devServer.
  // The stats-settings are just to keep the console as
  // clean as possible:
  devServer: {
    contentBase: path.join(process.cwd(), "dist"),
    open: true,
    stats: { children: false, maxModules: 0 }
  },

  // Now the plugins:
  plugins: [

    // To clean up dist folder:
    CleanWebpackPlugin {},

    // Just a fancy progressbar
    WebpackBarPlugin {},
    CopyPlugin {
      patterns: [
        // Here a list of all static files will be
        // generated except HTML files and optionally
        // the favicon source file
      ],
    },

    // To put the parsed CSS files in a separate file:
    MiniCssExtractPlugin {
      options: {
        filename: 'my-library.css',
      }
    },

    // For linting CSS files:
    new StyleLintPlugin({
      files: "./src/**/*.css"
    }),

    // This plugin allows to set the publicPath for dynamic imports
    // into a global variable. With this you can install your library
    // anywhere you want and the dynamic imports will work:
    WebpackRequireFrom {
      options: { variableName: 'pathToMyLibrary', suppressErrors: true },
    },

    // Needed to load vue files
    VueLoaderPlugin {},

    // Parse all HTML files in static folder.
    //
    // By default the HtmlWebPlugin use the defined webpack loader.
    // But this loader (html-loader) do not parse variable names like
    // "<%= htmlWebpackPlugin.tags.headTags %>". We could define a
    // loader chain like described here: https://github.com/webpack-contrib/html-loader/issues/195
    // or force to use the "ejs-loader" like done here:
    HtmlWebpackPlugin {
      options: {
        template: '!!ejs-loader!./static/index.html',
        filename: 'index.html',
        inject: true,
      },
    },
    // ... this will be repeated for every HTML file

    // Generate favoicons. Inject the links to them always in all
    // HTML files parsed by HtmlWebpackPlugin (which will be all the
    // files in the static folder):
    FaviconsWebpackPlugin {
      options: {
        inject: 'force',
        prefix: 'favicon',
        logo: './static/logo.png'
      }
    },

    // This plugin will set the webpack "externals" option
    // and furthermore copy the needed libraries to the output folder
    // and inject HTML files with the needed tags.
    ccWebpackExternalsPlugin {
      useCdn: args.externalsCdn ? true : false,
      getCdnPath: finalBoilerplateConfig.bundle.getCdnPath,
    },

    // Banner Plugin will be used only in production mode
    BannerPlugin({
      banner: finalBoilerplateConfig.production.banner,
    })

  ],

  // Now the modules:
  module: {
    rules: [
      // *.vue: vue-loader
      { test: /\.vue$/, exclude: /node_modules/, loader: 'vue-loader' },

      // *.html: html-loader
      // This is to import (statically or dynamic) of HTML files.
      // For now images or other external assets will not be considered.
      {
        test: /\.html$/,
        exclude: /node_modules/,
        loader: 'html-loader'
      },

      // *.ts: eslint > ts > babel
      // ESLint will use the special configuration from ".eslintrc".
      // The ts-loader is prepared to work with vue files with <script lang="ts">
      // The ts-compiler will translate them into JavaScript and babel
      // will translate them into browser compatible JavaScript:
      {
        test: /\.ts$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader',
            options: { presets: [ '@babel/preset-env' ], plugins: [] }
          },
          {
            loader: 'ts-loader',
            options: { appendTsSuffixTo: [ /.vue$/ ] }
          },
          { loader: 'eslint-loader' }
        ]
      },

      // *.css: postcss > css-loader > extract-plugin
      // Postcss will translate them into browser compatible CSS
      // and css-loader include them (and their dependecies) into
      // the final build. For now images or other url targets
      // will not be processed.
      {
        test: /\.css$/,
        exclude: /node_modules/,
        use: [
          MiniCssExtractPlugin.loader,
          {
            loader: 'css-loader',
            options: { url: false, importLoaders: 1 }
          },
          'postcss-loader'
        ]
      },

      // *.js: eslint > babel
      // ESLint will use the special configuration from ".eslintrc".
      // Babel finally translate them into browser compatible JavaScript:
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: [
          {
            loader: 'babel-loader',
            options: { presets: [ '@babel/preset-env' ], plugins: [] }
          },
          { loader: 'eslint-loader' }
        ]
      }
    ]
  }
}

Current Tags

  • 1.3.1                                ...           latest (6 days ago)

27 Versions

  • 1.3.1                                ...           6 days ago
  • 1.3.0                                ...           8 days ago
  • 1.2.24                                ...           a month ago
  • 1.2.23                                ...           a month ago
  • 1.2.22                                ...           a month ago
  • 1.2.21                                ...           a month ago
  • 1.2.20                                ...           a month ago
  • 1.2.19                                ...           a month ago
  • 1.2.18                                ...           a month ago
  • 1.2.17                                ...           a month ago
  • 1.2.16                                ...           a month ago
  • 1.2.15                                ...           2 months ago
  • 1.2.14                                ...           2 months ago
  • 1.2.13                                ...           2 months ago
  • 1.2.12                                ...           2 months ago
  • 1.2.11                                ...           2 months ago
  • 1.2.10                                ...           2 months ago
  • 1.2.8                                ...           2 months ago
  • 1.2.7                                ...           2 months ago
  • 1.2.6                                ...           2 months ago
  • 1.2.5                                ...           2 months ago
  • 1.2.4                                ...           5 months ago
  • 1.2.3                                ...           5 months ago
  • 1.2.2                                ...           5 months ago
  • 1.2.1                                ...           5 months ago
  • 1.2.0                                ...           5 months ago
  • 1.1.0                                ...           5 months ago
Maintainers (1)
Downloads
Today 0
This Week 0
This Month 80
Last Day 0
Last Week 39
Last Month 136
Dev Dependencies (0)
None
Dependents (0)
None

Copyright 2014 - 2017 © taobao.org |