Skip to content

Commit

Permalink
Merge pull request #683 from ckeditor/dll-integration
Browse files Browse the repository at this point in the history
Feature (utils): Added a module (`builds.getDllPluginWebpackConfig()`) that produces the webpack configuration for DLL. See ckeditor/ckeditor5#8395.
  • Loading branch information
pomek authored Feb 1, 2021
2 parents 3d7d5c2 + e2aa892 commit 7dad0ad
Show file tree
Hide file tree
Showing 6 changed files with 297 additions and 0 deletions.
136 changes: 136 additions & 0 deletions packages/ckeditor5-dev-utils/lib/builds/getdllpluginwebpackconfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/**
* @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md.
*/

'use strict';

const path = require( 'path' );
const webpack = require( 'webpack' );
const TerserPlugin = require( 'terser-webpack-plugin' );
const bundler = require( '../bundler' );
const styles = require( '../styles' );
const tools = require( '../tools' );

/**
* Returns a webpack configuration that creates a bundle file for the specified package. Thanks to that, plugins exported
* by the package can be added to ready-to-use builds.
*
* @param {Object} options
* @param {String} options.themePath An absolute path to the theme package.
* @param {String} options.packagePath An absolute path to the root directory of the package.
* @param {String} options.manifestPath An absolute path to the DLL manifest file.
* @param {Boolean} options.isDevelopmentMode Whether to build a dev mode of the package.
* @returns {Object}
*/
module.exports = function getDllPluginWebpackConfig( options ) {
const packageName = tools.readPackageName( options.packagePath );

const webpackConfig = {
mode: options.isDevelopmentMode ? 'development' : 'production',

performance: { hints: false },

entry: path.join( options.packagePath, 'src', 'index.js' ),

output: {
library: [ 'CKEditor5', getGlobalKeyForPackage( packageName ) ],

path: path.join( options.packagePath, 'build' ),
filename: getIndexFileName( packageName ),
libraryTarget: 'umd',
libraryExport: 'default'
},

optimization: {
minimize: false
},

plugins: [
new webpack.BannerPlugin( {
banner: bundler.getLicenseBanner(),
raw: true
} ),
new webpack.DllReferencePlugin( {
manifest: require( options.manifestPath ),
scope: 'ckeditor5/src',
name: 'CKEditor5.dll'
} )
],

module: {
rules: [
{
test: /\.svg$/,
use: [ 'raw-loader' ]
},
{
test: /\.css$/,
use: [
{
loader: 'style-loader',
options: {
injectType: 'singletonStyleTag',
attributes: {
'data-cke': true
}
}
},
{
loader: 'postcss-loader',
options: styles.getPostCssConfig( {
themeImporter: {
themePath: options.themePath
},
minify: true
} )
}
]
}
]
}
};

if ( options.isDevelopmentMode ) {
webpackConfig.devtool = 'source-map';
} else {
webpackConfig.optimization.minimize = true;

webpackConfig.optimization.minimizer = [
new TerserPlugin( {
terserOptions: {
output: {
// Preserve CKEditor 5 license comments.
comments: /^!/
}
},
extractComments: false
} )
];
}

return webpackConfig;
};

/**
* Transforms the package name (`@ckeditor/ckeditor5-foo-bar`) to the name that will be used while
* exporting the library into the global scope.
*
* @param {String} packageName
* @returns {String}
*/
function getGlobalKeyForPackage( packageName ) {
return packageName
.replace( /^@ckeditor\/ckeditor5?-/, '' )
.replace( /-([a-z])/g, ( match, p1 ) => p1.toUpperCase() );
}

/**
* Extracts the main file name from the package name.
*
* @param packageName
* @returns {String}
*/
function getIndexFileName( packageName ) {
return packageName.replace( /^@ckeditor\/ckeditor5?-/, '' ) + '.js';
}
10 changes: 10 additions & 0 deletions packages/ckeditor5-dev-utils/lib/builds/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/**
* @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md.
*/

'use strict';

module.exports = {
getDllPluginWebpackConfig: require( './getdllpluginwebpackconfig' )
};
1 change: 1 addition & 0 deletions packages/ckeditor5-dev-utils/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ module.exports = {
workspace: require( './workspace' ),
translations: require( './translations/index' ),
bundler: require( './bundler/index' ),
builds: require( './builds/index' ),
styles: require( './styles/index' )
};
4 changes: 4 additions & 0 deletions packages/ckeditor5-dev-utils/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,13 @@
"pofile": "^1.0.9",
"postcss": "^7.0.17",
"postcss-import": "^12.0.0",
"postcss-loader": "^3.0.0",
"postcss-mixins": "^6.2.0",
"postcss-nesting": "^7.0.0",
"raw-loader": "^4.0.1",
"shelljs": "^0.8.1",
"style-loader": "^1.2.1",
"terser-webpack-plugin": "^3.0.2",
"through2": "^3.0.1"
},
"devDependencies": {
Expand Down
123 changes: 123 additions & 0 deletions packages/ckeditor5-dev-utils/tests/builds/getdllpluginwebpackconfig.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md.
*/

'use strict';

const path = require( 'path' );
const chai = require( 'chai' );
const sinon = require( 'sinon' );
const mockery = require( 'mockery' );
const webpack = require( 'webpack' );
const TerserPlugin = require( 'terser-webpack-plugin' );
const expect = chai.expect;

describe( 'builds/getDllPluginWebpackConfig()', () => {
let sandbox, stubs, getDllPluginWebpackConfig;

const manifest = {
content: {
'../../node_modules/lodash-es/_DataView.js': {
id: '../../node_modules/lodash-es/_DataView.js',
buildMeta: {
buildMeta: 'namespace',
providedExports: [
'default'
]
}
}
}
};

beforeEach( () => {
sandbox = sinon.createSandbox();

stubs = {
tools: {
readPackageName: sandbox.stub()
}
};

sandbox.stub( path, 'join' ).callsFake( ( ...args ) => args.join( '/' ) );

mockery.enable( {
useCleanCache: true,
warnOnReplace: false,
warnOnUnregistered: false
} );

mockery.registerMock( '../tools', stubs.tools );
mockery.registerMock( '/manifest/path', manifest );

getDllPluginWebpackConfig = require( '../../lib/builds/getdllpluginwebpackconfig' );
} );

afterEach( () => {
mockery.disable();
sandbox.restore();
} );

it( 'returns the webpack configuration in production mode by default', () => {
stubs.tools.readPackageName.returns( '@ckeditor/ckeditor5-dev' );

const webpackConfig = getDllPluginWebpackConfig( {
packagePath: '/package/path',
themePath: '/theme/path',
manifestPath: '/manifest/path'
} );

expect( webpackConfig ).to.be.an( 'object' );

expect( webpackConfig.mode ).to.equal( 'production' );

expect( webpackConfig.entry ).to.equal( '/package/path/src/index.js' );
expect( webpackConfig.output.library ).to.deep.equal( [ 'CKEditor5', 'dev' ] );
expect( webpackConfig.output.path ).to.equal( '/package/path/build' );
expect( webpackConfig.output.filename ).to.equal( 'dev.js' );

expect( webpackConfig.plugins ).to.be.an( 'array' );
expect( webpackConfig.plugins.length ).to.equal( 2 );
expect( webpackConfig.plugins[ 1 ] ).to.be.an.instanceOf( webpack.DllReferencePlugin );

expect( webpackConfig.plugins[ 1 ].options.manifest ).to.deep.equal( manifest );
expect( webpackConfig.plugins[ 1 ].options.scope ).to.equal( 'ckeditor5/src' );
expect( webpackConfig.plugins[ 1 ].options.name ).to.equal( 'CKEditor5.dll' );

expect( webpackConfig.optimization.minimize ).to.equal( true );
expect( webpackConfig.optimization.minimizer ).to.be.an( 'array' );
expect( webpackConfig.optimization.minimizer.length ).to.equal( 1 );

// Due to versions mismatch, the `instanceof` check does not pass.
expect( webpackConfig.optimization.minimizer[ 0 ].constructor.name ).to.equal( TerserPlugin.name );
} );

it( 'transforms package with many dashes in its name', () => {
stubs.tools.readPackageName.returns( '@ckeditor/ckeditor5-html-embed' );

const webpackConfig = getDllPluginWebpackConfig( {
packagePath: '/package/path',
themePath: '/theme/path',
manifestPath: '/manifest/path'
} );

expect( webpackConfig ).to.be.an( 'object' );
expect( webpackConfig.output.library ).to.deep.equal( [ 'CKEditor5', 'htmlEmbed' ] );
expect( webpackConfig.output.filename ).to.equal( 'html-embed.js' );
} );

it( 'does not minify the destination file when in dev mode', () => {
stubs.tools.readPackageName.returns( '@ckeditor/ckeditor5-dev' );

const webpackConfig = getDllPluginWebpackConfig( {
packagePath: '/package/path',
themePath: '/theme/path',
manifestPath: '/manifest/path',
isDevelopmentMode: true
} );

expect( webpackConfig.mode ).to.equal( 'development' );
expect( webpackConfig.optimization.minimize ).to.equal( false );
expect( webpackConfig.optimization.minimizer ).to.be.undefined;
} );
} );
23 changes: 23 additions & 0 deletions packages/ckeditor5-dev-utils/tests/builds/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
/**
* @license Copyright (c) 2003-2021, CKSource - Frederico Knabben. All rights reserved.
* For licensing, see LICENSE.md.
*/

'use strict';

const chai = require( 'chai' );
const expect = chai.expect;

describe( 'builds', () => {
let tasks;

beforeEach( () => {
tasks = require( '../../lib/builds/index' );
} );

describe( 'getDllPluginWebpackConfig()', () => {
it( 'should be a function', () => {
expect( tasks.getDllPluginWebpackConfig ).to.be.a( 'function' );
} );
} );
} );

0 comments on commit 7dad0ad

Please sign in to comment.